JavaScript执行上下文、执行栈、作用域链与闭包介绍

2025/3/8
深入探讨JavaScript中执行上下文、执行栈、作用域链与闭包的概念,包括执行上下文的类型与组成、执行栈的工作原理、作用域链的变量查找机制以及闭包与执行上下文的关系,帮助理解JavaScript运行机制。
JavaScript执行上下文类型关系图,执行栈工作原理流程图,作用域链查找变量示意图,闭包示例代码逻辑图

在 JavaScript 中,执行上下文(Execution Context)执行栈(Execution Stack) 是理解代码执行机制的核心概念。它们共同决定了代码的执行顺序和作用域链的构建。


1. 执行上下文(Execution Context)

执行上下文是 JavaScript 代码执行的环境,包含了当前代码执行所需的所有信息。每当 JavaScript 引擎执行一段代码时,都会创建一个新的执行上下文。

执行上下文的类型

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

    • 这是默认的、最外层的执行上下文。
    • 在浏览器环境中,全局上下文是 window 对象。
    • 在 Node.js 环境中,全局上下文是 global 对象。
    • 全局上下文在脚本首次运行时创建,并且在整个程序生命周期中一直存在。
  • 函数执行上下文(Function Execution Context)

    • 每当调用一个函数时,都会为该函数创建一个新的执行上下文。
    • 每个函数调用都会创建一个独立的执行上下文。
  • Eval 执行上下文(Eval Execution Context)

    • 使用 eval() 函数执行的代码会创建一个独立的执行上下文。
    • 由于 eval() 的性能和安全问题,现代开发中很少使用。

执行上下文的组成

每个执行上下文包含以下内容:

  • 变量环境(Variable Environment)
    • 存储变量、函数声明和函数参数。
    • 使用 var 声明的变量会被提升(hoisted)。
  • 词法环境(Lexical Environment)
    • 存储块级作用域变量(如 letconst 声明的变量)。
    • 词法环境是一个嵌套结构,用于实现作用域链。
  • this 绑定(This Binding)
    • 确定当前上下文中 this 的值。
    • 在全局上下文中,this 指向全局对象(如 windowglobal)。
    • 在函数上下文中,this 的值取决于函数的调用方式。

2. 执行栈(Execution Stack)

执行栈(也称为调用栈,Call Stack)是一个后进先出(LIFO)的栈结构,用于管理执行上下文的创建和销毁。

执行栈的工作原理

  1. 初始阶段
    • 当 JavaScript 引擎开始执行代码时,会创建一个全局执行上下文,并将其推入执行栈。
  2. 函数调用阶段
    • 每当调用一个函数时,会为该函数创建一个新的执行上下文,并将其推入执行栈。
    • 函数执行完成后,其执行上下文会从栈中弹出。
  3. 栈顶执行
    • 执行栈顶部的执行上下文是当前正在执行的上下文。
  4. 栈清空
    • 当所有代码执行完毕时,全局执行上下文也会从栈中弹出,程序结束。

示例代码

function first() {
    console.log("First function");
    second();
}

function second() {
    console.log("Second function");
    third();
}

function third() {
    console.log("Third function");
}

first();

执行栈的变化

  1. 全局执行上下文被推入栈。
  2. 调用 first()first 的执行上下文被推入栈。
  3. first 中调用 second()second 的执行上下文被推入栈。
  4. second 中调用 third()third 的执行上下文被推入栈。
  5. third 执行完毕,其上下文从栈中弹出。
  6. second 执行完毕,其上下文从栈中弹出。
  7. first 执行完毕,其上下文从栈中弹出。
  8. 全局执行上下文从栈中弹出,程序结束。

3. 作用域链(Scope Chain)

每个执行上下文都有一个关联的作用域链,用于解析变量和函数。作用域链是基于词法环境的嵌套结构,决定了变量的查找顺序。

  • 当访问一个变量时,JavaScript 引擎会首先在当前执行上下文的词法环境中查找。
  • 如果未找到,则沿着作用域链向上查找,直到全局执行上下文。
  • 如果仍未找到,则抛出 ReferenceError

4. 闭包与执行上下文

闭包是 JavaScript 中一个重要的概念,它与执行上下文密切相关。闭包是指一个函数能够访问其词法作用域中的变量,即使该函数在其词法作用域之外执行。

function outer() {
    let outerVar = "I'm outer!";
    function inner() {
        console.log(outerVar); // 访问外部函数的变量
    }
    return inner;
}

const closureFunc = outer();
closureFunc(); // 输出: I'm outer!

在这个例子中,inner 函数形成了一个闭包,它保留了对外部函数 outer 的词法环境的引用。


总结

  • 执行上下文 是代码执行的环境,包含变量环境、词法环境和 this 绑定。
  • 执行栈 是一个后进先出的栈结构,用于管理执行上下文的创建和销毁。
  • 作用域链 决定了变量的查找顺序。
  • 闭包 是函数与其词法环境的结合,允许函数访问其外部作用域中的变量。

理解这些概念对于掌握 JavaScript 的运行机制至关重要,尤其是在调试复杂代码或优化性能时。

上次更新:

相关文章

npx完全指南:前端开发必备工具详解 | 20年架构师深度解析

本文由20年前端架构师深入解析npx工具,涵盖其核心功能、优势、高级用法、最佳实践及与npm/yarn的区别比较,帮助开发者掌握这一现代前端开发利器。

·前端开发

<处理关联数据的最佳实践:Article 与 Tags 的关系 | 开发指南>

<本文详细介绍了在开发中处理关联数据(如 Article 和 Tags 的多对多关系)的最佳实践,包括拆分业务逻辑、使用事务保证数据一致性、合理设计关联表结构、批量操作、幂等性和乐观锁等关键要点,并提供了基于 mysql2 和 Sequelize 的代码示例。>

·后端开发

Astro 静态站点生成器:构建高性能网站的最佳选择

Astro 是一个专注于构建快速、轻量级网站的静态站点生成器,支持多种前端框架,采用岛屿架构减少 JavaScript 加载,提升性能。

·前端开发

MySQL外键约束详解:维护数据一致性与完整性

本文详细介绍了MySQL中的外键约束(Foreign Key Constraint),包括其基本概念、创建方法、作用、级联操作、限制、修改与删除方法、查看方式以及最佳实践。通过合理使用外键约束,可以有效管理数据库中的数据关系,确保数据的准确性和可靠性。

·后端开发

MySQL JSON数据类型支持与使用指南 | 详细解析与示例

本文详细解析了MySQL从5.7版本开始支持的JSON数据类型,包括版本支持、创建JSON字段、插入与查询JSON数据、修改JSON数据、生成JSON、索引优化、性能与应用场景、注意事项及示例全流程。

·后端开发

SQL JOIN、LEFT JOIN 和 RIGHT JOIN 的区别与应用场景详解

本文详细介绍了 SQL 中 JOIN、LEFT JOIN 和 RIGHT JOIN 的区别,包括它们的作用、语法、示例以及实际应用场景,帮助读者更好地理解和使用这些连接方式。

·后端开发

Weex 跨平台移动开发框架:核心特性与使用指南

Weex 是由阿里巴巴开源的跨平台移动开发框架,支持使用 Vue.js 或 Rax 构建高性能的 iOS、Android 和 Web 应用。本文详细解析了 Weex 的核心特性、架构、工作流程、组件和模块、开发工具、优缺点、应用场景及未来发展。

·前端开发

ECharts 与 DataV 数据可视化工具对比分析 | 选择指南

本文详细对比了 ECharts 和 DataV 两个常用的数据可视化工具,包括它们的设计目标、优缺点、使用场景和技术栈,帮助读者根据具体需求选择合适的工具。

·前端开发

前端部署后通知用户刷新页面的常见方案 | 单页应用更新提示

本文介绍了在前端部署后通知用户刷新页面的几种常见方案,包括WebSocket实时通知、轮询检查版本、Service Worker版本控制、版本号对比、自动刷新、使用框架内置功能以及第三方库。每种方案的优缺点和示例代码均有详细说明。

·前端开发

TypeScript 映射类型常见问题与解决方案 | 提升代码维护性

本文探讨了在使用 TypeScript 时,映射类型的不当使用可能导致的问题,如代码难以维护、类型推断不准确或性能问题,并提供了相应的解决方案和最佳实践。

·编程语言