JavaScript只使用词法作用域,不支持动态作用域;变量查找依据函数定义位置而非调用位置,作用域链在定义时静态确定,确保行为可预测、支持闭包与静态分析。

JavaScript 不采用动态作用域,它只支持词法作用域(即静态作用域)。所谓“动态作用域”在 JavaScript 中并不存在,不是它的特性,也不参与实际执行逻辑。
动态作用域的本质是什么
动态作用域指函数在运行时,根据**调用位置**(即谁调用了它)来决定变量查找路径。变量值取决于函数被调用时所处的执行上下文,而不是函数写在哪里。
- 查找顺序是沿着调用栈向上找:先看当前函数内部 → 再看直接调用它的函数作用域 → 再看上一层调用者,依此类推
- 典型代表语言:Bash、Emacs Lisp(部分模式)、Perl(可选)
- 举例(Bash):x=1; foo() { echo $x; }; bar() { local x=2; foo; }; bar → 输出 2,因为
foo是在bar内部被调用的,就“继承”了bar的局部变量
JavaScript 怎么体现“不支持动态作用域”
JS 始终按函数定义的位置确定作用域链,与调用位置无关。这是硬性规则,无法绕过。
- 即使函数被传参、赋值给变量、作为回调执行,它的作用域链仍固定不变
-
foo()定义在全局,就永远从全局开始查;定义在outer()里,就永远先查outer的作用域 - 常见误判场景:把
this的动态绑定混淆为作用域动态——this确实是运行时决定的,但它和作用域(变量查找)是两套独立机制
为什么 JS 明确排除动态作用域
词法作用域让代码行为可预测、易推理,对工具链(如 IDE 提示、打包、压缩、静态分析)至关重要。
立即学习“Java免费学习笔记(深入)”;
- 编辑器能在写代码时就标出变量来源,不用等运行
- 闭包能可靠捕获外层变量,不会因调用方式改变而失效
- 模块系统(ESM)依赖词法结构做静态导入解析,动态作用域会破坏这一基础
容易混淆的几个点
有些现象看似“动态”,其实仍是词法作用域下的正常表现:
- var 声明提升 + 函数内访问外部变量:不是因为调用位置,而是因为定义时已连入作用域链
- 箭头函数不绑定 this,但作用域仍是词法的:它继承的是外层函数的词法作用域,不是调用时的
- eval 或 with 语句:它们确实引入运行时作用域变化,但属于被严格限制的非标准、不推荐使用的特例,不能代表 JS 的作用域模型


















