标准答案
- 词法作用域:函数能访问哪些变量,主要由代码定义位置决定,而不是由调用位置决定。函数创建时会记住外层词法环境,这也是闭包能访问外层变量的基础。
- 作用域链:读取变量时,引擎会先查当前作用域的词法环境;当前作用域找不到,就沿外层环境一层一层向上查,直到全局作用域。如果最终仍然找不到绑定,读取会抛 ReferenceError。
- 概念区分:作用域链查的是变量绑定,原型链查的是对象属性,this 绑定决定函数执行时的上下文。它们是三套不同机制,不能混在一起解释。
- 块级作用域: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 创建的块级作用域,把所有作用域都理解成函数级。