标准答案

  1. 词法作用域:函数能访问哪些变量,主要由代码定义位置决定,而不是由调用位置决定。函数创建时会记住外层词法环境,这也是闭包能访问外层变量的基础。
  2. 作用域链:读取变量时,引擎会先查当前作用域的词法环境;当前作用域找不到,就沿外层环境一层一层向上查,直到全局作用域。如果最终仍然找不到绑定,读取会抛 ReferenceError。
  3. 概念区分:作用域链查的是变量绑定,原型链查的是对象属性,this 绑定决定函数执行时的上下文。它们是三套不同机制,不能混在一起解释。
  4. 块级作用域:let 和 const 在 if、for、try/catch 这类代码块中会创建块级绑定,var 不会创建块级作用域。

题目解析

词法作用域、闭包、var/let、this 经常放在一起理解。词法作用域强调“定义位置”,this 强调“调用方式”,原型链强调“对象属性委托”。

块级作用域也要讲到。let 和 const 在 if、for、try/catch 这类代码块中会创建块级绑定,var 不会创建块级作用域。

代码示例

下面例子里函数在哪里定义,比在哪里调用更重要。

JavaScript
const name = 'global'

function createPrinter() {
  const name = 'local'

  return function printName() {
    console.log(name)
  }
}

const print = createPrinter()
print() // local

常见误区

  • 误以为函数在哪里调用,就能访问哪里的局部变量。JavaScript 是词法作用域,不是动态作用域。
  • 把作用域链和原型链混为一谈。前者查变量,后者查对象属性。
  • 忽略 let/const 创建的块级作用域,把所有作用域都理解成函数级。

作者信息