遮蔽是词法作用域查找中内层同名变量屏蔽外层变量的现象:编译期建立作用域链,内层声明使同名标识符绑定到自身,不覆盖外层变量,仅阻断访问路径。

嵌套作用域中同名变量的遮蔽效应,本质是 JavaScript 词法作用域查找规则的自然结果:从当前作用域开始,逐层向外查找,一旦在某一层找到同名变量声明,就停止向上搜索——这个“先被找到”的变量,就遮蔽了外层所有同名变量。
遮蔽不是覆盖,而是屏蔽访问路径
外层变量依然存在、未被修改、也未被销毁。只是在内层作用域里,你无法通过那个变量名访问到它。
- 比如全局有 let count = 0,函数内再写 let count = 100,两者内存地址不同,互不影响
- 函数内修改 count,只改自己的副本;函数执行完,外层 count 还是 0
- 若用 var 声明,因函数提升和作用域特性,行为略有不同,但遮蔽逻辑一致
遮蔽发生在声明时,由编译期确定
JavaScript 引擎在编译阶段(代码执行前)就已建立好作用域链。只要某个块或函数内部出现了同名 let、const 或 var 声明,该作用域及其子作用域中对该标识符的所有引用,都会绑定到这个新声明上。
- let x = 5; 在块内声明,会遮蔽外层任意位置的 x
- 即使外层 x 是 const,内层用 let x 仍可遮蔽——类型和声明方式不阻碍遮蔽
- 未声明直接赋值(如 x = 10)不会触发遮蔽,而是可能创建全局变量或报错(严格模式)
常见易错点:对象属性 vs 变量名
遮蔽只作用于变量标识符本身,不延伸到对象属性。这点容易混淆。
- 外层 let obj = {val: 1},内层 let obj = {val: 2} → 遮蔽生效,两个 obj 完全无关
- 但若内层没重新声明 obj,只写 obj.val = 99 → 访问的是外层 obj,修改其属性,不触发遮蔽
- 误以为 obj.val 被遮蔽,其实遮蔽的是 obj 这个变量名,不是它的属性
调试时怎么确认是否发生遮蔽
最直接的方法是在关键位置加 console.log,并配合浏览器开发者工具的作用域面板观察:
- 在嵌套函数开头打印变量,看输出值是否符合内层预期
- 打开 Sources 面板,在断点处查看右侧 Scope 区域:Local 下有该变量,说明已被遮蔽;若只在 Closure 或 Global 出现,说明未被遮蔽
- 把内层声明临时注释掉,再运行对比行为变化,能快速验证遮蔽是否存在
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











