之前提到的使用 eval
和 with
能创建所谓的 动态作用域,介绍它们只是为了和 词法作用域 形成对比,出于性能和代码可维护角度考虑,千万别用它们来写代码!
动态作用域 和后面要讲的 this 机制有异曲同工之妙。所谓的 动态,即指在 代码运行时,区别于 代码书写时 的 静态:
function foo () {
console.log(a); // 2
}
function bar () {
var a = 3;
foo();
function baz () {
console.log(a); // 3
}
baz();
}
var a = 2;
bar();
👆在 foo
中关于变量 a
的 RHS 是属于 词法作用域 的范畴,即在 foo
书写时就确定了其作用域是全局作用域;同理于 baz
,其书写时的作用域是 函数作用域(bar)。因此 foo()
输出 2
,baz
输出 3
。
如果是 动态作用域,当 foo
执行时,其输出的结果应该是 3
,因为理论上它的作用域链是基于函数的 调用栈(call-stack) 而非链上嵌套的 词法作用域。
清晰的讲,JS并没有实际上所谓的 动态作用域,而 this
只是某种类似 动态作用域 的机制而已。
关键的区别:词法作用域是建立在写代码时,动态作用域是建立在代码运行时。前者关心函数是在哪儿 声明(declared) 的,后者关心函数是在哪儿 调用(called) 的。