前言
词法作用域顾名思义就是在词法阶段就决定好的作用域,就是你写代码时就决定好的(变量、块作用域写的位置)
作用域气泡
function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar( b * 3 );
}
foo( 2 ); // 2, 4, 12
以上面代码为例:
可见它们是由编写位置所致。
变量查找是从当前作用域逐层往上查询直到全局作用域。若是查询到了第一个就停止。它只查询一级变量(a.b.c只查询a,余下的交给对象属性访问规则)。若是不同层级作用域有相同名字的变量,那么上层就会被屏蔽。
函数的词法作用域只与其所声明的位置有关,与调用位置无关。
欺骗词法作用域eval/with
eval
这家伙就是可以把一段字符串解析成函数代码。这样子若是传入声明变量的字符串代码,那么就可以修改在词法分析阶段就已经完备的词法作用域。它的特点是让代码好像就在那一样。
setTimeout、new Function()均有此效果,不过后者要安全些。
with
with也可以修改词法作用域,与其说是修改不如说是凭空生成。它的特点是接受传入变量(通常是对象),然后以其属性作为作用域之内的标识符,生成新的词法作用域以达到修改已存在的词法作用域。
其内标识符均是LHS查询,若是传入的对象无引用的属性,那么会往上冒泡。
值得注意的是,with内的变量声明会添加在with语句所在的作用域。
这俩家伙最好不要使用。因为本来在词法分析阶段就决定好的作用域有了这俩货就变得不能预测,导致引擎无法在编译阶段对作用域查找进行优化(因为引擎为了谨慎起见会认为优化无效)