定义

作用域是指程序源代码中定义变量的区域。

作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。

JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。

编译

在编译阶段会有以下3个步骤:

  1. 分词/词法分析(Tokenizing/Lexing)
    将由字符组成的字符串分解成有意义的代码块(词法单元/token)。
  2. 解析/语法分析(Parsing)
    将语法单元流转换成一个由元素逐渐嵌套所组成的代表了程序语法结构的树,被称为“抽像语法树”(Abstract Syntax Tree, AST)。
  3. 代码生成
    将AST转换成可执行代码的过程。

当然在实际中,远不止这样简单,在其中有很多性能优化等的相关工作。

词法作用域 (Lexical Scope)

词法作用域也就是在词法阶段定义的作用域,也就是说词法作用域在代码书写时就已经确定。

每个函数都有自己的词法作用域,词法作用域保存在自身函数属性 [[Scope]] 中,在该 [[Scope]] 中会预先包含至全局变量对象的作用域链。

可通过 evalwith 来改变词法作用域,但不建议使用。

词法作用域中存放着代表变量或函数的标识符。

看以下示例:

  1. var a = 10
  2. function fn() {
  3. console.log(a)
  4. }
  5. function run() {
  6. var a = 20
  7. fn()
  8. }
  9. run() // 打印结果:10

如果按按动态作用域来说,a 的值应该是 20,但 JavaScript 是静态作用域,所以在编译时就确认了函数自身的作用域,在编译时函数 fn 里没有变量 a,但它的父执行上下文是全局上下文,在全局上下文中变量 a 的值是10。

动态作用域 (Dynamic Scope)

thisJavaScript 中是在调用时确认的,跟动态作用域很像。