当前位置: 首页 > news >正文

JavaScript的执行上下文和执行栈

在 JavaScript 中,执行上下文(Execution Context)和执行栈(Execution Stack)是理解 JavaScript 代码执行过程中的两个非常关键的概念。它们是 JavaScript 引擎在运行代码时,管理执行流程和变量作用域的核心机制。下面将详细解释这两个概念。

1. 执行上下文(Execution Context)

定义:

执行上下文是 JavaScript 代码执行时的环境,决定了代码如何被解析和执行。每当 JavaScript 函数被调用、脚本被加载时,都会创建一个新的执行上下文。

执行上下文的类型:

JavaScript 中主要有三种类型的执行上下文:

  1. 全局执行上下文

    • 默认创建的执行上下文,代码最外层的上下文。
    • 在浏览器中,this 指向 window 对象。
    • 任何未定义在函数内的变量或函数,都会被添加到全局上下文中。
  2. 函数执行上下文

    • 每次调用一个函数时,都会为该函数创建一个新的执行上下文。
    • 每个函数有自己独立的上下文,并且在执行过程中会有自己的变量、参数和内部函数。
  3. eval 执行上下文(较少用):

    • 当使用 eval() 函数时,JavaScript 会将字符串内容当作代码执行,这时会创建一个独立的执行上下文。
执行上下文的生命周期:

每个执行上下文的生命周期大致可以分为两个阶段:

  1. 创建阶段

    • 变量对象(Variable Object)/ 词法环境(Lexical Environment)
      • 变量、函数声明和参数被存储在执行上下文的变量对象中。
    • 作用域链(Scope Chain)
      • 作用域链确定了当前执行代码在哪些环境中可以访问变量。
    • this 绑定
      • this 会根据上下文不同绑定到不同的对象(如全局对象或调用该函数的对象)。
  2. 执行阶段

    • 变量赋值、函数执行,代码依次执行。
示例:
var name = 'Alice';function sayHello() {var greeting = 'Hello';console.log(greeting + ', ' + name);
}sayHello();
  1. 全局执行上下文

    • 创建变量 name,并赋值为 'Alice'
    • sayHello 函数被声明但尚未执行。
  2. 函数执行上下文(当调用 sayHello() 时):

    • 创建 greeting 变量,并赋值为 'Hello'
    • 执行 console.log,通过作用域链可以访问全局变量 name

2. 执行栈(Execution Stack)

定义:

执行栈(也称作调用栈,Call Stack)是用来管理多个执行上下文的栈结构。当一个函数被调用时,其对应的执行上下文会被推入执行栈;当函数执行完毕后,执行上下文会从栈中弹出。

执行栈的特点:
  • 后进先出(LIFO):执行栈遵循后进先出的原则,最后进入的执行上下文最先被执行完毕。
  • 全局执行上下文位于栈底:全局执行上下文是整个程序最开始执行的环境,它始终处于栈底。
执行过程:
  • 当 JavaScript 引擎开始执行代码时,会首先创建全局执行上下文,并将其推入执行栈。
  • 当函数被调用时,会为该函数创建一个新的执行上下文,并推入栈中。
  • 当函数执行完毕时,执行上下文会从栈中弹出,控制权返回到上一个执行上下文。
示例:
function multiply(x, y) {return x * y;
}function square(n) {return multiply(n, n);
}function printSquare(num) {var result = square(num);console.log(result);
}printSquare(5);
执行栈过程:
  1. 全局执行上下文被创建并推入执行栈。
  2. 执行到 printSquare(5),为 printSquare 创建执行上下文并推入栈中。
  3. printSquare 中调用 square(5),创建 square 的执行上下文并推入栈中。
  4. square(5) 中调用 multiply(5, 5),创建 multiply 的执行上下文并推入栈中。
  5. multiply 函数执行完毕,执行上下文从栈中弹出,返回控制权给 square
  6. square 执行完毕,执行上下文弹出,返回控制权给 printSquare
  7. printSquare 执行完毕,执行上下文弹出,返回控制权给全局执行上下文。
  8. 最终,程序执行完毕,全局执行上下文也会弹出。
可视化:
执行栈变化:
1. [ 全局执行上下文 ]
2. [ 全局执行上下文, printSquare 执行上下文 ]
3. [ 全局执行上下文, printSquare 执行上下文, square 执行上下文 ]
4. [ 全局执行上下文, printSquare 执行上下文, square 执行上下文, multiply 执行上下文 ]
5. [ 全局执行上下文, printSquare 执行上下文, square 执行上下文 ]
6. [ 全局执行上下文, printSquare 执行上下文 ]
7. [ 全局执行上下文 ]
8. [ ]

3. 执行上下文与执行栈的关系

  • 执行上下文是 JavaScript 代码的执行环境。每当 JavaScript 引擎执行代码时,会为当前代码块(如全局代码、函数调用)创建一个新的执行上下文。
  • 执行栈是管理这些执行上下文的结构。函数调用会在执行栈中按顺序推入新的执行上下文,执行完毕后从栈中弹出。

4. 执行上下文和执行栈的使用场景

  • 递归函数:递归调用函数时,每次递归都会推入一个新的执行上下文,形成多个嵌套的执行栈帧。当递归结束时,执行上下文逐个弹出。

    示例:

    function factorial(n) {if (n === 1) return 1;return n * factorial(n - 1);
    }factorial(5);
    

    每次递归调用 factorial 都会创建一个新的执行上下文并推入执行栈。

  • 异步代码执行:异步代码(如 setTimeout)并不会立即创建新的执行上下文,而是被放入任务队列中,当栈清空后再执行。

    示例:

    console.log('Start');setTimeout(() => {console.log('Async task');
    }, 0);console.log('End');
    

    输出顺序是:

    Start
    End
    Async task
    

    因为 setTimeout 的回调在全局上下文结束后才会被执行。

5. 总结

  • 执行上下文:是 JavaScript 代码的运行环境,决定了代码执行时的变量、作用域和 this 绑定。主要有三种类型:全局执行上下文、函数执行上下文和 eval 执行上下文。

  • 执行栈:是管理执行上下文的栈结构,遵循后进先出的原则,用来记录函数调用和返回的顺序。

  • 执行栈和执行上下文是 JavaScript 代码运行的核心机制,掌握它们有助于理解 JavaScript 的函数调用、作用域链和异步执行等高级特性。


http://www.mrgr.cn/news/36260.html

相关文章:

  • Spring 的依赖注入原理
  • 【裸机装机系列】15.kali(ubuntu)-重装linux步骤
  • 使用openpyxl轻松操控Excel文件
  • Pandas和Seaborn可视化详解
  • PLC Twincat3 对传感器数据滑动平均滤波
  • 微软宣布弃用WSUS,企业用户尽早准备替换方案
  • javase复习day33网络编程
  • Spring Boot 中实现动态列导入讲解和案例示范
  • JPA+Thymeleaf
  • 《Detection of Tea Leaf Blight in Low-Resolution UAV Remote Sensing Images》论文阅读
  • [java][git]git学习
  • LocalStorage
  • Java面向对象(二)(类的方法)(自己学习整理的资料)
  • 2-103 基于matlab的光电信号下血氧饱和度计算
  • nginx部署手册
  • Linux 系统安全工具简介
  • 【机器学习】Flux.jl 生态
  • 静电势能(electrostatic potential energy)和电势(electric potential)
  • Windows (rust) vulkan 画一个三角形: 窗口创建与渲染初始化
  • 如何创建一个包含多个列的表?