JavaScript作用域链是函数定义时词法环境逐级向上连接形成的查找路径,创建时即固定[[Environment]]引用,运行时按就近原则向上查找直至全局对象。

JavaScript作用域链的本质,是函数在定义时所处的词法环境(Lexical Environment)逐级向上连接形成的查找路径。它决定了变量和函数在运行时从哪里获取值——不是看函数在哪执行,而是看它在哪定义。
作用域链在函数创建时就已确定
每个函数对象内部都保存着一个 [[Environment]] 内部属性,指向其定义时所在的作用域(即外层词法环境)。这个链接关系在函数被创建时就固定下来,与调用位置无关。
- 闭包就是依赖这个机制:内层函数即使在外部执行,仍能访问其定义时的外层变量
- 注意:箭头函数没有自己的 this 和 arguments,但它同样遵循词法作用域,继承外层函数的 [[Environment]]
变量查找遵循“就近原则 + 向上逐级查找”
当访问一个变量时,JS 引擎会先在当前执行上下文的词法环境中找;找不到就顺着作用域链向上一级环境查找,直到全局对象(浏览器中是 window);若全程未找到,就报 ReferenceError。
- 查找只发生在运行时,但链的结构在定义时就锁定了
- var 声明会被提升,但作用域仍是函数级;let/const 有暂时性死区(TDZ),但它们的作用域链查找逻辑一致
- 同名变量会屏蔽外层变量,比如内层用 let x = 10,外层的 x 就不可见了
全局作用域是作用域链的终点
全局作用域没有外层环境,它的外部引用为 null。所有顶层声明(非函数内)都挂载在全局对象上(严格模式下部分例外),因此作用域链最终会停在这里。
立即学习“Java免费学习笔记(深入)”;
- Node.js 中全局对象是 global,浏览器中是 window(或 self)
- 通过 with 或 eval 可临时修改作用域链,但强烈不建议使用,会影响性能和可读性
调试作用域链的小技巧
虽然不能直接打印作用域链,但可通过以下方式间接观察:
- 在 Chrome DevTools 的断点处,右侧“Scope”面板会显示当前作用域链各层的变量
- 利用闭包返回外层变量,验证是否真能访问到定义时的环境
- 把函数 toString() 后查看源码位置,再结合调用栈反推定义位置










