JavaScript只有词法作用域,没有动态作用域;词法作用域在代码解析阶段就由函数定义位置静态确定,执行时沿预设作用域链查找变量,与调用位置无关。

JavaScript 只有词法作用域,没有动态作用域。所谓“词法”指的是代码写在哪儿、嵌套结构如何,就决定了变量能被谁访问;它和函数在哪调用、谁调用它完全无关。执行上下文是运行时的概念,而作用域(尤其是词法作用域)是在代码解析阶段就固定下来的——两者不是同一层面的机制,但执行上下文会沿着早已确定的词法作用域链去查找变量。
词法作用域:写代码时就定死了
函数内部能访问哪些变量,取决于它在源码中定义的位置,而不是执行位置。JS 引擎在解析阶段(parse time)就根据花括号、函数声明、块结构等静态结构,构建出一条作用域链。
- 外层函数声明的 let/const/function 会创建新词法环境,内层函数自动持有对外层环境的引用
- 即使把函数赋值给变量、传入其他函数、甚至 setTimeout 延迟执行,它依然沿用定义时的作用域
- 箭头函数不创建自己的词法环境,直接复用外层函数的 this 和词法作用域
动态作用域:JS 中并不存在
动态作用域是指变量查找依赖调用栈——看函数当前在哪个执行上下文中被调用。这在标准 JavaScript 中并不存在。常见的误解来源有两个:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- this 的绑定方式:this 确实是动态的(取决于调用方式),但它只影响 this 值,不影响 var/let/const 变量的查找
- eval 和 with:它们会临时改变词法环境的静态性,导致变量查找行为变得“类似动态”,但这是特例且已被严格限制,不应作为理解基础
执行上下文与作用域链的关系
每当函数执行,就会创建一个执行上下文;它包含变量对象(VO)、this 绑定、作用域链三个核心部分。其中“作用域链”不是运行时生成的,而是从函数创建时就继承下来的词法环境链。
立即学习“Java免费学习笔记(深入)”;
- 全局执行上下文的作用域链只含全局词法环境
- 函数执行上下文的作用域链 = 自己的词法环境 + 外层函数的词法环境 + … + 全局词法环境
- 变量查找就是沿着这条链逐级向上,直到找到或报 ReferenceError
一个典型例子帮你区分
let x = "global"; function foo() { console.log(x); } function bar() { let x = "bar"; foo(); } bar(); // 输出 "global",不是 "bar"因为 foo 定义在全局作用域,它的词法作用域链里只有全局环境;调用位置(bar 内部)对变量查找毫无影响。这就是词法作用域的铁律——定义位置决定一切。

















