词法作用域 - 你不知道的 JS

  1. 编译
  2. 词法阶段
    1. 词法作用域
    2. 查找范围

编译

在传统编译语言的流程中,程序中的一段源代码在执行之前会经历三个步骤,统称为“编译”。
编译可以分为三个阶段

  1. 词法分析。例如,var a = 2; 这段代码通常会被分解成为下面这些词法单元:vara=2;
  2. 语法分析。这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树。这个树被称为“抽象语法树”(Abstract Syntax Tree,AST)在线生成 AST
  3. 代码生成。将 AST 转换为可执行代码的过程被称为代码生成。简单来说就是有某种方法可以将 var a = 2; 的 AST 转化为一组机器指令,用来创建一个叫作 a 的变量(包括分配内存等),并将一个值储存在 a 中。

词法阶段

词法作用域

词法作用域就是定义在词法阶段的作用域。
换句话说,词法作用域是由你在写代码时将变量和块作用域写在哪里来决定的,因此当词法分析器处理代码时会保持作用域不变(大部分情况下是这样的)。

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 b c
  3. bar 创建的作用域,一个标识符,c

这三个作用域由其对应的作用域块代码写在哪里决定,它们是逐级包含的。而且是严格包含,没有哪个作用域同时出现在两个作用域里。

查找范围

作用域查找会在找到第一个匹配的标识符时停止。在多层的嵌套作用域中可以定义同名的标识符,这叫作 “遮蔽效应”(内部的标识符“遮蔽” 了外部的标识符)。抛开遮蔽效应,作用域查找始终从运行时所处的最内部作用域开始,逐级向外或者说向上进行,直到遇见第一个匹配的标识符为止。

无论函数在哪里被调用,也无论它如何被调用,它的词法作用域都只由函数被声明时所处的位置决定。

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


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论。
我的空间