词法作用域由函数定义位置决定,作用域链从内层函数逐级向上锁定至全局,不随调用位置改变;块级作用域(let/const)纳入链中,var 不创建块作用域;同名变量仅遮蔽外层,不覆盖。

词法作用域在函数嵌套中,本质是“函数在哪写的,就认谁当爹”——变量查找路径完全由代码书写时的嵌套结构决定,和函数在哪里执行、被谁调用毫无关系。
作用域链按定义位置逐级向上锁定
内层函数一定义,它的作用域链就固定了:从自身开始,依次是外层函数、再外层函数,最后到全局。这个链条不会因为函数被传给别的地方、或者被回调、被定时器触发而改变。
- 哪怕 inner() 被 return 出来,在别处调用,它依然只查当初写在哪个函数里
- 如果 inner 写在 global 下,它跳过所有函数,直接查 window/globalThis
- 如果 inner 写在 outer 函数内部,那 outer 的变量就是它第一站要找的地方
查找过程严格遵循层级顺序
引擎执行 console.log(x) 时,不是“猜”x 在哪,而是机械地走链:
- 先查 inner 自己的词法环境(参数、let/const/var 声明)
- 没找到,就跳到 outer 的词法环境里找
- 还没找到,继续往上,直到全局;中途任一节点找到就停,不再继续
不会跳级,也不会绕开父级去“抄近路”。这种确定性正是词法作用域可靠的基础。
块级作用域也参与链式结构
ES6 的 if、for、{} 块只要用了 let 或 const,就生成一个新作用域节点,也会被纳入作用域链。
- function fn() { if (true) { let x = 1; } console.log(x); } → 报错,x 不在 fn 自身作用域,也不在全局,链上找不到
- function fn() { if (true) { var x = 1; } console.log(x); } → 输出 1,因为 var 不创建块级作用域,x 属于 fn 函数作用域
同名变量只是遮蔽,不是覆盖
内层声明同名变量,只是让外层那个“暂时隐身”,并不销毁或修改它。
- let a = 1; function f() { let a = 2; console.log(a); } → 输出 2
- 删掉 f 里的 let a = 2,输出立刻变成 1,说明外层 a 始终存在
- var 也有遮蔽效果,但因提升机制,行为更隐蔽;let/const 在声明前访问会进 TDZ 直接报错
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











