在这篇博客中不定期连载比较“冷门”(其实就是自己用的比较少)的前端技术备忘,用作日后打脸
逗号运算符是诸如此类的的运算符:
1, 2, 3, 4
var a = (1, 2) // a=2
var a, b
for (var i = 0, j = 10; i < j; i++){}
(1, g_t=44, 3+4, 4)
(1, eval)('2') // 2
这个运算符的作用是将表达式连接起来,里面的各个表达式都会独自计算,返回最后一个表达式的运算结果。优先级处于最低,运算方向是从左到右,常常会和括号()
连用,以提高运算符等级。
需要注意的是,以下的表达式是错的
var test = 1, 4
因为=
的优先级先于,
,赋值先于逗号执行,然而左边赋值又不是一个正规的赋值表达式,因此会抛出Uncaught SyntaxError: Unexpected number
的错误。改法如下
var test = (1, 4)
需要注意的是,以上的,
不能当做人类语法中的逗号使用,要看做一个程序上的运算符,和^&|
这些类似。
另外不是所有在js中的逗号都是逗号运算符,比如函数参数add(1, 2, 3, 4, 5)
连等可读性不太好,不过经常在一些框架中看到有人使用
a = b = {foo: 4}
=
运算符是从右至左,因此拆开后就是
b = {foo: 4}
a = b
即a和b的内存地址相同,共同指向{foo: 4}
CSP(Content Security Policy),内容安全策略,可以在http头中的Content-Security-Policy或者html中的meta标签中定义。
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
以上标签可以阻止在设置之外的脚本运行,有效的防止xss。
其中有个配置名为script-src
字段有个值为unsafe-eval
,设置后不允许将字符串当做代码执行。比如不能使用eval
、setTimeout
、setInterval
和Function
等函数。
禁止以上函数可能会影响基于字符串模板的一些框架,本人在阅读vue源码的过程中发现如下代码,可以在脚本中检测是否开启了CSP的unsafe-eval
,并给予友好提示:
// detect possible CSP restriction
try {
new Function('return 1');
} catch (e) {
if (e.toString().match(/unsafe-eval|CSP/)) {
warn$$1(
'It seems you are using the standalone build of Vue.js in an ' +
'environment with Content Security Policy that prohibits unsafe-eval. ' +
'The template compiler cannot work in this environment. Consider ' +
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
'templates into render functions.'
);
}
}
这两个函数共同点就是可以执行字符串代码,区别在于作用域的不同。
另外,new Function的语法如下
new Function ([arg1[, arg2[, ...argN]],] functionBody)
eval
的作用域在于当前上下文, new Funciton
是在自己的匿名函数中的作用域,即私有作用域
var a,b,c;
(function(){
eval('var b = 2');
(1, eval)('var c = 3');
(new Function('var a = 4'))();
document.write('
a: ' + a); // a: undefined
document.write('
b: ' + b); // b: 2
document.write('
c: ' + c); // c: 3
})()
document.write('
a: ' + a); // a: undefined
document.write('
b: ' + b); // b: undefined
document.write('
c: ' + c); // c: 3
另外值得一提的是,eval通过不同的调用方式可以灵活的改变其作用域
eval('...') // 当前作用域
window.eval('...') // window作用域
eval.call(vm, '...') // 'vm作用域'
(1, eval)(...) // window作用域
同样在vue框架中看到大量使用的一种对象声明方式。
区别于直接{}
,这样生成的对象没有上级作用域,因此没有Object原型上的toString,valueOf等方法。在框架中使用的好处是减少可能的全局污染带来的影响,因为作者会实现自己的toString这些方法。
在控制台中敲进void 0 === undefined
,会显示true,因为void
多少都返回的是undefined。
在es5之前undefined
是可以被重写的,因此用void 0
指代undefined
会更准确