作用域有两种工作模型:
第一种是最为普遍的,被大多数编程语言所采用的词法作用域
第二种叫作动态作用域
词法作用域就是定义在词法阶段的作用域。换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变。
作用域气泡由其对应的作用域块代码写在哪里决定,它们是逐级包含的。
查找
作用域查找首先从最内部的作用域,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止。
作用域查找会在找到第一个匹配的标识符时停止。
function foo(a) { var b = a * 2; function bar(c) { console.log( a, b, c ); } bar( b * 3 ); } foo( 2 ); // 2, 4, 12
(1)包含着整个全局作用域,其中只有一个标识符: foo 。
(2)包含着 foo 所创建的作用域,其中有三个标识符: a 、 bar 和 b 。
(3)包含着 bar 所创建的作用域,其中只有一个标识符: c 。
欺骗词法
(1)eval
在执行 eval(..) 之后的代码时,引擎并不“知道”或“在意”前面的代码是以动态形式插入进来,并对词法作用域的环境进行修改的。引擎只会如往常地进行词法作用域查找。
(2)with
with 可以将一个没有或有多个属性的对象处理为一个完全隔离的词法作用域,因此这个对象的属性也会被处理为定义在这个作用域中的词法标识符。
另外一个不推荐使用 eval(..) 和 with 的原因是会被严格模式所影响(限制)。 with 被完全禁止,而在保留核心功能的前提下,间接或非安全地使用eval(..) 也被禁止了。