JavaScript作用域链是函数执行时动态生成的向上逐级搜索路径,由函数定义位置决定,起点为当前函数作用域,依次指向外层直至全局;变量查找从内到外,找到即止,内层变量会遮蔽外层同名变量。

JavaScript的作用域链,本质是引擎在查找变量时遵循的一条“向上逐级搜索的路径”。它不是预先定义好的静态结构,而是在函数执行时动态生成的,由当前执行上下文的词法作用域(即函数定义时所处的位置)决定。
作用域链是怎么形成的
每当一个函数被调用,JS引擎会为它创建一个执行上下文,并基于该函数的定义位置构建作用域链。这条链的起点是当前函数自己的作用域(活动对象/词法环境),然后依次指向外层函数的作用域,最终到达全局作用域。
- 作用域链只跟“函数在哪写的”有关,跟“函数在哪调用的”无关(这就是词法作用域的核心)
- 闭包之所以能访问外层变量,正是因为内部函数的作用域链中保留了对外层词法环境的引用
- 全局代码也有作用域链,只包含全局词法环境本身
变量查找过程:从内到外,找到即止
当代码中使用一个变量(比如 console.log(x)),JS引擎会沿着当前执行上下文的作用域链,从头开始逐级查找:
- 先查当前作用域(如函数内部声明的 let x 或参数)
- 没找到,就去上一级作用域(外层函数)查
- 继续向上,直到全局作用域;如果全局也没有,就报 ReferenceError
注意:一旦找到第一个匹配的变量名就停止搜索,不会继续往上找——这意味着内层变量会“遮蔽”(shadow)外层同名变量。
立即学习“Java免费学习笔记(深入)”;
常见误区提醒
很多人误以为作用域链和原型链类似,或者认为它随调用栈变化。其实关键点在于:
- 不是调用链,是定义链:函数在哪里定义,决定了它的外层是谁
- var、let/const 的查找行为一致,区别只在是否允许重复声明、是否存在暂时性死区等,不影响作用域链本身的结构
- this 不参与作用域链查找:this 是运行时绑定的对象,和变量查找机制完全独立
动手验证的小技巧
- 在函数内部打断点,暂停执行后,在“Scope”面板里能看到当前作用域链的层级
- 每个层级会显示变量名和值,最上面是 Local,往下是 Closure(如果有闭包),最后是 Global
- 修改外层变量再观察,能验证闭包确实持有对外层环境的引用,而非拷贝










