嵌套函数的作用域链由定义位置决定,而非调用位置;查找变量时从自身词法环境开始,逐级向上至全局,同名变量遮蔽外层但不覆盖,块级作用域(let/const)也参与链式查找。

嵌套函数访问外部变量,靠的是作用域链——不是看“谁调用了它”,而是看“它写在哪”。函数定义时的位置,就锁死了它的查找路径。
作用域链的起点是函数定义处
内层函数在哪儿写的,它的“上一层”就是谁。哪怕它被传到别的地方执行,这条链也不会变。
- 比如
function inner() { console.log(x); }写在function outer() { let x = 100; ... }里面,那它的上一级作用域就是outer的词法环境 - 如果
inner是写在全局里,那它一上来就查全局,根本不会去翻outer里的x - 调用位置不影响查找路径:即使
outer()里调用inner(),而inner又被另一个函数other()调用,它依然只认自己出生的地方
查找过程严格按层级顺序
引擎从当前函数自己的词法环境开始找,没找到就往上跳一级,再没找到就继续跳,直到全局;一旦命中同名变量就停,不会继续往上。
- 先查自己作用域(参数、
let/const/var声明) - 再查外层函数作用域(包括它的参数和变量)
- 最后查全局作用域(
window或globalThis) - 全程不跨级跳:不会跳过
outer直接去查全局,也不会绕开父级去找“更远的亲戚”
同名变量会遮蔽,不是覆盖
内层声明了同名变量,只是让外层那个“暂时看不见”,并不会改掉它。
-
let a = 1; function f() { let a = 2; console.log(a); }输出2,因为f自己的a在链最前端 - 如果删掉
f里的let a = 2,输出就变成1,说明外层的a一直都在,只是被遮住了 -
var也有遮蔽效果,但因提升机制,行为稍复杂;let/const在声明前访问会进 TDZ,直接报错
注意块级作用域也参与链式查找
ES6 的 if、for 等块,只要用了 let/const,就构成一个新作用域节点,也会被纳入链中。
-
function fn() { if (true) { let x = 99; } console.log(x); }会报错,因为if块是fn的子级,但x不在fn自己的作用域里 - 而
function fn() { if (true) { var x = 99; } console.log(x); }能输出99,因为var不创建块级作用域,x实际属于fn函数作用域
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











