JavaScript只使用词法作用域,不支持动态作用域;其作用域链在函数定义时就已固定,变量查找严格按代码嵌套结构从内到外逐层进行,同名变量会遮蔽外层变量,找不到则抛ReferenceError。

JavaScript 只使用词法作用域,不支持动态作用域。理解这个事实,是掌握变量查找机制的关键起点。
词法作用域:看“写在哪”,不是“在哪调”
函数的作用域链,在它被定义的那一刻就固定了,和后续怎么调用、在哪调用完全无关。引擎按代码嵌套的物理结构一层层向上找变量。
- 比如 bar 在全局定义,即使被 foo 内部调用,它仍沿定义时的链查全局的 x
- 而 inner 在 outer 内部定义,就能自然访问 outer 中的变量,哪怕返回后在别处执行
- 这种静态可预测性,让代码行为稳定,也支撑了闭包——内部函数能持续持有对外部变量的引用
动态作用域:只存在于对比中,JS 不走这条路
它依赖调用栈:函数运行时,沿着当前执行路径向上找变量。JS 没有这种机制,但了解它能反衬出词法作用域的设计意图。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- Bash 或某些 Lisp 中,bar 被 foo 调用,就会优先取 foo 里的 x,哪怕 bar 是在全局写的
- JS 做不到这点——let x = "global"; function bar() { console.log(x); } function foo() { let x = "local"; bar(); } foo(); 输出一定是 "global"
- 混淆常来自 this:它的绑定是动态的,但变量查找仍是词法的。两者不能混为一谈
遮蔽与作用域链:查找过程的真实细节
变量查找不是模糊匹配,而是严格按层级逐级向外推进,同名变量会遮蔽外层变量。
立即学习“Java免费学习笔记(深入)”;
- 块级作用域(let/const)也能遮蔽,不只是函数
- 查找只针对一级标识符:访问 obj.a.b 时,词法作用域只找 obj;a 和 b 是对象属性访问,不走作用域链
- 找不到变量会抛 ReferenceError,而不是静默失败或回退到其他上下文
为什么 JS 坚持词法作用域?
这不是随意选择,而是为了可维护性与确定性。
- 开发者读代码时,无需追踪调用路径,就能推断变量来源
- 工具(如 IDE 自动补全、ESLint)能静态分析作用域关系
- 闭包、模块封装、工厂函数等关键模式都建立在此基础之上

















