人人都会AI编程

3.1 执行上下文:全局上下文、函数上下文、Eval 上下文

更新时间:2026-07-11

当 JavaScript 引擎开始执行一段代码时,它并不是“看到一行就执行一行”,而是先建立一套有序的追踪和管理机制。这套机制的核心就是执行上下文(Execution Context)——可以把它理解为代码运行时的“工作环境”,它记录了当前代码能够访问到的变量、函数、参数以及 this 的值。

每次代码执行都离不开执行上下文,不同类型的代码会创建不同类型的执行上下文。JavaScript 引擎通过一个执行上下文栈(调用栈) 来管理这些上下文——新的上下文被推入栈顶,执行完毕后弹出销毁,程序恢复到上一个上下文继续执行。

理解执行上下文是理解作用域、闭包、变量提升、this 绑定等一系列核心机制的起点。

3.1.1 全局执行上下文(Global Execution Context)

全局上下文是 JavaScript 代码运行的最外层环境。当一段 .js 文件开始执行,或者你在 <script> 标签、浏览器控制台中输入代码时,首先创建的就是全局执行上下文。

在全局上下文中:

  • 全局对象被创建:浏览器中为 window,Node.js 中为 global
  • this 指向全局对象(严格模式下为 undefined,但全局代码中的 this 仍为全局对象)。
  • 所有在全局作用域中声明的 var 变量和函数声明,都会成为全局对象的属性;而 letconst 声明则挂在全局块作用域下,不会成为全局对象的属性。
var a = 1;
let b = 2;

console.log(window.a); // 1  (浏览器环境)
console.log(window.b); // undefined

全局上下文的生命周期
从脚本开始执行时创建,直到页面关闭或程序退出时销毁。一个程序中只有一个全局执行上下文。

3.1.2 函数执行上下文(Function Execution Context)

调用一次函数,都会创建一个专属的函数执行上下文。这是 JavaScript 中最常见的上下文类型。注意:函数定义时并不创建上下文,只有在调用时才创建。

函数上下文中会包含:

  • 参数传递:形参作为局部变量绑定,arguments 对象在非箭头函数中可用。
  • 内部声明的变量和函数:它们只在这个函数被调用期间存在。
  • 作用域链:记录当前上下文可以访问的外部环境,这是第 3.4 节要深入讨论的内容。
  • this 的绑定:根据调用方式确定的 this 值(详见第 5 章)。

下面是一个简单的例子:

function greet(name) {
  let message = "Hello, " + name;
  return message;
}

greet("Alice"); 
// 调用时创建函数执行上下文
// 完成后上下文弹出销毁,message 不再存在

函数执行上下文的创建和销毁非常频繁,这也是为什么不能过度依赖在函数内部创建大量大对象——频繁的创建和垃圾回收会影响性能。

3.1.3 Eval 执行上下文(Eval Execution Context)

eval() 函数中执行的代码也会创建自己的执行上下文。eval 可以接收一段字符串,并在当前作用域中执行它:

let x = 1;
eval("let y = 2; console.log(x + y)"); // 3

eval 上下文属于一种特殊、动态的执行环境,它会修改当前作用域,并且会降低引擎执行效率(因为引擎无法事先对其进行优化)。在严格模式下,eval 有自己独立的作用域,不会污染外层变量。

为什么不建议使用 eval

  1. 性能代价:JavaScript 引擎的许多优化(如作用域分析、预测)在面对 eval 时会失效,因为引擎无法预测 eval 中的字符串会改变什么。
  2. 安全风险:执行任意字符串内容极易导致代码注入攻击。
  3. 可读性极差:字符串内嵌代码难以调试和维护。

除非在极其特殊的元编程场景下(例如实现一个沙箱环境),现代 JavaScript 开发中几乎不会再使用 eval 执行上下文。本书后续也不会再围绕它展开详细讨论,你只需要知道它的存在和风险即可。

3.1.4 执行上下文的生命周期

每个执行上下文(无论全局、函数还是 eval)都会经历相似的三个阶段:

  1. 创建阶段
  • 创建变量对象(Variable Object):收集当前作用域中的变量声明、函数声明、形参等。
  • 建立作用域链:确定当前上下文可以向哪些外部环境查找变量。
  • 确定 this 的指向。
  • 此时代码还未执行,但变量和函数已经被“提升”(var 变量初始化为 undefined,let/const 变量进入暂时性死区)。
  1. 执行阶段
  • 逐行执行代码,进行变量赋值、运算、函数调用等操作。
  1. 销毁阶段
  • 执行完成后从调用栈弹出,所占内存被标记为可回收,由垃圾回收机制处理。

这三个阶段中,最容易被忽视却又最重要的,就是创建阶段的变量对象和工作原理(变量提升的本质),下一节 3.2 将带你深入了解执行栈的运行机制,3.3 节会详细拆解变量对象与活动对象,看看提升到底是怎么发生的。