ES6通过let/const引入真正的块级作用域,底层依托词法环境与声明式环境记录实现绑定、TDZ及迭代独立绑定。

JavaScript在ES6中通过let和const关键字真正引入了块级作用域,解决了ES5及之前仅靠函数作用域带来的变量提升、重复声明、循环绑定等长期痛点。其核心不是语法糖,而是运行时环境对词法环境(Lexical Environment)和作用域链的底层重构。
块级作用域的底层载体:词法环境与环境记录
ES6规范中,每个代码块(如{...}、if、for、switch)在执行时都会创建一个独立的**词法环境(Lexical Environment)**,该环境包含:
- 环境记录(Environment Record):实际存储变量与绑定关系的数据结构,块级作用域使用声明式环境记录(Declarative Record),支持不可重复绑定、暂时性死区(TDZ)等语义;
- 外部环境引用(Outer Lexical Environment):指向外层(父级)词法环境,构成作用域链。
这与函数作用域使用的词法环境同构,但生命周期更短——块级环境在块执行结束时可被回收(若无闭包引用),而函数环境需等待函数执行上下文销毁。
let/const如何触发块级绑定行为
let和const声明在进入块时被“绑定”,但不会被初始化(即不赋值)。直到执行到声明语句所在位置,才完成初始化。这一间隙形成暂时性死区(Temporal Dead Zone, TDZ):
立即学习“Java免费学习笔记(深入)”;
- 在TDZ内访问变量会抛出
ReferenceError,而非返回undefined; - TDZ覆盖整个块的起始到声明语句之间,包括嵌套子块的前置部分;
-
typeof对TDZ中的变量也不安全(区别于var的“安全”假象)。
例如:console.log(x); let x = 1; 直接报错,因为x已绑定但未初始化。
for循环中的块级作用域细节
ES6明确要求每次for迭代都应创建新的词法环境(尤其对let/const声明):
-
for (let i = 0; i console.log(i), 0); }输出0, 1, 2,因每次迭代的i是不同绑定; - 若用
var,则所有回调共享同一个i,输出3, 3, 3; - 注意:
for...in和for...of同样适用该规则,且const在循环中必须确保每次迭代不重复赋值(如for (const x of arr)合法,但for (const i = 0; i 语法错误)。
与函数作用域、全局作用域的交互逻辑
块级作用域并非完全隔离,它遵循标准的作用域链查找规则:
- 变量查找从当前块环境开始,逐级向外查找至全局环境;
- 块内用
let/const声明同名变量会**遮蔽(shadow)** 外层变量,但不影响外层绑定本身; - 全局块(脚本顶层)中用
let/const声明的变量不会成为window属性(区别于var),这是由全局词法环境的特殊实现决定的。
这种设计让块级作用域既保持封装性,又无缝融入现有作用域模型,无需改变引擎整体执行逻辑。










