javascript的词法环境和执行上下文是理解语言运行机制的重要基础,两者紧密关联却又承担着不同的功能,下面分别展开说明。

什么是javascript词法环境
词法环境是javascript用来管理标识符(变量、函数、参数等)和对应值之间映射关系的一种结构,它在代码编写阶段就已经确定,这也是“词法”这个名称的由来。每个词法环境由两部分组成:
- 环境记录:用来存储当前作用域内所有标识符的声明和对应的值,比如变量声明、函数声明都会存放在这里。
- 对外部词法环境的引用:指向外层作用域的词法环境,这个引用构成了作用域链的基础。
我们可以通过一段简单的代码来理解词法环境的结构:
// 全局词法环境的环境记录会存储全局变量a和函数foo
var a = 1;
function foo() {
var b = 2;
// foo函数内部的词法环境的环境记录存储局部变量b,外部引用指向全局词法环境
console.log(a + b);
}
什么是javascript执行上下文
执行上下文是javascript代码执行时的运行环境,每当javascript引擎执行一段可执行代码(比如全局代码、函数代码、eval代码)时,都会创建一个对应的执行上下文。执行上下文的生命周期分为创建阶段和执行阶段:
创建阶段
在创建阶段会完成三件事:
- 创建词法环境,也就是我们前面提到的词法环境结构。
- 创建变量环境,变量环境其实是词法环境的一个特殊副本,专门用来存储var声明的变量(因为var存在变量提升的特性)。
- 确定this的指向。
执行阶段
执行阶段会按照代码顺序执行语句,给变量赋值、执行函数调用等操作。
不同类型的执行上下文对应不同的执行场景:
| 执行上下文类型 | 触发场景 |
|---|---|
| 全局执行上下文 | js代码开始运行时创建,整个页面生命周期只有一个 |
| 函数执行上下文 | 每次函数被调用时创建,函数执行完毕后会被销毁 |
| eval执行上下文 | 执行eval函数内的代码时创建,实际开发中很少使用 |
词法环境和执行上下文的关系
两者的核心关系是:词法环境是执行上下文的组成部分,执行上下文在创建阶段会生成对应的词法环境,用来管理当前执行环境下的标识符映射。
具体可以从以下几个角度理解:
- 执行上下文是一个更宏观的运行环境概念,它包含了词法环境、变量环境、this指向等多个部分,而词法环境只是其中负责标识符管理的一部分。
- 每个执行上下文都有自己独立的词法环境,全局执行上下文对应全局词法环境,每个函数执行上下文对应函数自己的词法环境。
- 词法环境中的外部引用,和执行上下文的嵌套调用关系对应:当函数A内部调用函数B时,函数B的执行上下文对应的词法环境的外部引用,会指向函数A执行上下文的词法环境。
我们可以通过闭包的例子来直观感受两者的关系:
function outer() {
var outerVar = '外部变量';
function inner() {
console.log(outerVar); // 可以访问outer的变量
}
return inner;
}
var innerFunc = outer();
innerFunc(); // 输出"外部变量"
上面的代码中,outer函数执行时创建了自己的执行上下文,对应的词法环境存储了outerVar变量。当outer执行完毕,它的执行上下文本来应该被销毁,但是inner函数的词法环境的外部引用指向了outer的词法环境,所以这个词法环境不会被回收,innerFunc调用时就能访问到outerVar,这就是闭包的原理,本质就是执行上下文销毁后,其对应的词法环境因为被引用而保留了下来。
常见误区说明
很多开发者会混淆词法环境和作用域的概念,这里简单区分:作用域是代码在编写时确定的可访问标识符的范围,是一个静态的概念;而词法环境是实现作用域机制的运行时结构,是动态创建的。执行上下文则是代码执行时的完整运行环境,词法环境只是它的一个组成部分。
另外需要注意,let和const声明的变量是存放在词法环境的环境记录中,而var声明的变量是存放在变量环境中,这也是var存在变量提升而let、const存在暂时性死区的原因,因为变量环境和词法环境的初始化时机不同。
javascript词法环境执行上下文作用域链修改时间:2026-07-09 04:54:10