第一部分 作用域和闭包 第二章 词法作用域

第二章 词法作用域

book

词法作用域

作用域有两种工作模型,一种是词法作用域,也是本章讨论的重点,另一种叫做动态作用域,Bash, Perl等语言仍在使用。

词法阶段

大部分标准语言编译器的第一个工作阶段叫做词法化也叫做单词化。词法作用域顾名思义就是定义在词法阶段的作用域。通俗一点说,词法作用域由写代码时将变量和块写在哪里来决定的。 例如:

function foo(a){
    var b = a * 2;
    function bar(c){
        console.log(a,b,c)
    }
    bar(b * 3)
}

foo(2); //2,3,12
  1. 包含着整个全局作用域,其中只有标识符: foo
  2. 包含着foo所创建的作用域,其中有三个标识符: a, bar, b
  3. 包含着bar所创建的作用域,其中有一个标识符: c

作用域由其对应的作用域块代码写在哪里决定,他们是逐级包含的。引擎在寻找标识符的时候会从当前作用域开始向上查找直到全局作用域为止。作用域查找会在找到第一个匹配的标识符时候停止。

在多层嵌套作用域中可以定义同名的标识符,这叫做遮蔽效应即内部标识符遮蔽外部标识符。

词法作用域查找只会查找一级标识符,比如a、b和c。如果代码中引用了foo.bar.baz,词法作用域查找只会试图查找foo标识符,找到这个变量后,对象属性访问规则会分别接管对bar和baz属性的访问。

欺骗词法

JavaScript中有两种机制可以欺骗词法作用域,不推荐使用,因为其会导致性能下降。

  1. eval: JavaScript中eval()函数接受一个字符串为参数,将其中的内容视为代码,这样就可以起到修改词法作用域的目的。而引擎并不知道代码是以动态形式插入进来的,只会如往常一样进行词法作用域查找。
  2. with: 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象本身。with 可以讲一个没有或者有多个属性的对象处理为一个完全隔离的词法作用域,因此这个对象的属性也会被定义为这个作用域中的词法标识符。

eval和with会导致引擎停止做任何优化,从而导致性能问题。并且严格模式下,这两个函数是禁用的。

Search

    Table of Contents