作用域与执行上下文
区分词法作用域与执行上下文,解释作用域链如何查找变量,并为闭包与提升打地基。
#synthesis
#growing
#dev
#javascript
#ecmascript
[!info] related notes
- 所属:语言基础 MOC
- 后续:闭包 · 执行上下文 · 变量提升 · var/let/const
作用域与执行上下文
这个概念为什么出现
“变量从哪来/为什么读到旧值/为什么 TDZ 报错”都混在口语“作用域”里。拆开后:
- 作用域:写代码结构决定的可见性规则(词法)
- 执行上下文:运行到某段代码时创建的运行环境
[!abstract] 一句话理解 作用域是编译/解析期定下的查词地图;执行上下文是运行时沿着地图真正找值的现场。
最小可运行示例
场景:折扣函数里的仓库税率
const warehouseTax = 0.03 // 当前脚本或模块的词法绑定
function priceWithTax(base) {
const serviceFee = 2 // 函数作用域
function finalize(total) {
// 教学点:finalize 词法上能看见 serviceFee 与 warehouseTax
return total + serviceFee + total * warehouseTax
}
return finalize(base)
}
console.log(priceWithTax(100))
期望:100 + 2 + 3 = 105。
再看块级:
function demo() {
if (true) {
let flag = 'inside'
}
// console.log(flag) // ReferenceError:块级作用域
}
核心模型
作用域类型
- 全局
- 函数
- 块(
let/const/class等) - 模块作用域
作用域链
内部函数查找标识符:自身环境 → 定义处的外层词法环境 → …;不会沿调用者的局部变量查找。闭包保留环境中的绑定,不是定义时的值快照;读取时仍可能见到后续赋值,或遇到 TDZ。
执行上下文包含(教学)
- 词法环境 / 变量环境
- 环境记录通过外层引用形成查找链\
- this 由相关环境记录提供;箭头函数没有独立的 this 绑定\
执行上下文是规范中的执行状态模型,不等于引擎必须分配某个固定物理对象。普通函数调用建立独立状态;进入块可创建词法环境,却不等于新函数调用。async/generator 还会暂停和恢复执行。
与提升关系
var 函数作用域 + 提升;let/const 暂时性死区。详见 变量提升。
常见误区
[!warning] 常见误区:作用域 = this this 是绑定规则;作用域是标识符解析。
本节总结
先分清“地图(作用域)”与“在地图上跑的一次调用(执行上下文)”,闭包与提升才不会玄学。
自测题
- 为什么内层函数能读外层
const? - 每次调用函数是否共享同一执行上下文?
参考答案
- 词法作用域链在定义时确定外层引用。
- 不共享;每次调用创建新上下文(闭包保留的是环境引用,不是单次栈帧本身的简单复用叙事)。