词法阶段
词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况下是这样的)。
嵌套作用域
function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar( b * 3 );
}
foo( 2 ); // 2, 4, 12
标识符 foo() 作用域
标识符 foo(a){} 作用域
标识符 bar(c) 作用域
欺骗词法
eval () 函数可以接受一个字符串为参数,并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。
setTimeout(..) 和 setInterval(..) 的第一个参数可以是字符串,字符串的内容可以被解释为一段动态生成的函数代码。
new Function(..) 函数的行为也很类似,最后一个参数可以接受代码字符串,并将其转化为动态生成的函数(前面的参数是这个新生成的函数的形参)。
function foo(str, a) {
eval( str ); // 欺骗!
console.log( a, b );
}
var b = 2;
foo( "var b = 3;", 1 ); // 1, 3
with
with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。
with坑
function foo(obj) {
with (obj) {
a = 2;
}
}
var o2 = {
b: 3
};
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2——不好,a 被泄漏到全局作用域上了!
o2中没有a 放入with中后 无法赋值 a=2就会变为全局变量 通过LHS来查找滴话。
性能
eval(..) 和 with 会在运行时修改或创建新的作用域,以此来欺骗其他在书写时定义的词法作用域。
JavaScript 引擎会在编译阶段进行数项的性能优化。其中有些优化依赖于能够根据代码的词法进行静态分析,并预先确定所有变量和函数的定义位置,才能在执行过程中快速找到标识符。
最悲观的情况是如果出现了 eval(..) 或 with,所有的优化可能都是无意义的,因此最简单的做法就是完全不做任何优化。
网友评论