【js面试】JavaScript中执行栈和执行上下文是什么?

发布于:2025-02-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

引言

在JavaScript中,**执行栈(Execution Stack)执行上下文(Execution Context)**是两个核心概念,它们共同决定了代码的执行顺序和作用域管理。理解这两个概念对于深入掌握JavaScript的运行机制至关重要。本文将详细介绍执行栈和执行上下文,并通过示例帮助读者更好地理解它们。


一、执行栈(Execution Stack)

执行栈,也称为调用栈(Call Stack),是JavaScript引擎用来跟踪函数调用的一种数据结构。它采用**后进先出(LIFO,Last-In-First-Out)**的原则来管理函数的执行顺序。

在这里插入图片描述

1.1 执行栈的工作原理
  1. 函数调用:当一个函数被调用时,JavaScript引擎会创建一个新的执行上下文,并将其压入执行栈的顶部。
  2. 执行上下文:执行栈顶部的执行上下文是当前正在执行的函数。
  3. 函数返回:当函数执行完毕,其执行上下文会从执行栈中弹出,控制权返回到调用该函数的位置。
  4. 错误处理:如果发生错误,JavaScript引擎会打印调用栈的跟踪信息,帮助开发者调试。
1.2 示例
function firstFunction() {
    console.log("First function");
    secondFunction();
}

function secondFunction() {
    console.log("Second function");
    thirdFunction();
}

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

firstFunction();

执行过程

  1. 调用 firstFunction(),将其执行上下文压入执行栈。
  2. firstFunction() 调用 secondFunction(),将 secondFunction() 的执行上下文压入执行栈。
  3. secondFunction() 调用 thirdFunction(),将 thirdFunction() 的执行上下文压入执行栈。
  4. thirdFunction() 执行完毕,其执行上下文从执行栈中弹出。
  5. secondFunction() 执行完毕,其执行上下文从执行栈中弹出。
  6. firstFunction() 执行完毕,其执行上下文从执行栈中弹出。

输出

First function
Second function
Third function

二、执行上下文(Execution Context)

执行上下文是JavaScript中用于跟踪代码执行环境的抽象概念。每个执行上下文都包含以下三个重要组成部分:

  1. 变量对象(Variable Object,VO):存储当前上下文中定义的变量和函数声明。
  2. 作用域链(Scope Chain):用于解析变量和函数的作用域。
  3. this 绑定:确定当前执行上下文中 this 的值。
2.1 执行上下文的类型
  1. 全局执行上下文(Global Execution Context)

    • 是默认的执行上下文,任何不在函数内部的代码都在全局执行上下文中执行。
    • 在浏览器中,this 指向 window 对象;在 Node.js 中,this 指向 global 对象。
  2. 函数执行上下文(Function Execution Context)

    • 每当一个函数被调用时,都会创建一个新的函数执行上下文。
    • 函数执行上下文包含函数内部的变量和参数。
  3. Eval 执行上下文(Eval Execution Context)

    • eval 函数内部执行的代码有自己的执行上下文。
    • 由于 eval 的使用可能带来安全性和性能问题,通常不推荐使用。
2.2 执行上下文的生命周期
  1. 创建阶段

    • 创建作用域链。
    • 创建变量对象,包括参数、函数声明和变量声明。
    • 确定 this 的值。
  2. 执行阶段

    • 变量赋值、函数执行等操作在此阶段进行。
  3. 销毁阶段

    • 函数执行完毕后,执行上下文从执行栈中弹出,相关资源被释放。
2.3 示例
var a = 10;

function foo(x) {
    var b = 20;
    function bar(y) {
        var c = 30;
        return x + y + c;
    }
    return bar(b);
}

console.log(foo(a));

执行过程

  1. 全局执行上下文

    • 变量对象:{ a: 10, foo: <function> }
    • 作用域链:全局作用域
    • this 指向全局对象
  2. 调用 foo(10),创建 foo 的函数执行上下文:

    • 变量对象:{ x: 10, b: 20, bar: <function> }
    • 作用域链:全局作用域 -> foo 作用域
    • this 指向全局对象
  3. 调用 bar(20),创建 bar 的函数执行上下文:

    • 变量对象:{ y: 20, c: 30 }
    • 作用域链:全局作用域 -> foo 作用域 -> bar 作用域
    • this 指向全局对象
  4. bar 函数执行完毕,其执行上下文从执行栈中弹出。

  5. foo 函数执行完毕,其执行上下文从执行栈中弹出。

  6. 最终输出 60


三、总结

理解执行栈和执行上下文对于掌握JavaScript的运行机制至关重要。执行栈负责管理函数的调用顺序,而执行上下文则提供了代码执行所需的环境信息。通过掌握这两个概念,开发者可以更有效地调试代码、优化性能,并避免常见的错误。
例子:

let a = 'Hello World!';

function first() {
    console.log('Inside first function');
    second();
    console.log('Again inside first function');
}

function second() {
    console.log('Inside second function');
}

first();

console.log('Inside Global Execution Context');

在这里插入图片描述
简单分析一下流程:

  • 创建全局上下文请压入执行栈
  • first 函数被调用,创建函数执行上下文并压入栈
  • 执行 first 函数过程遇到 second 函数,再创建一个函数执行上下文并压入栈
  • second 函数执行完毕,对应的函数执行上下文被推出执行栈,执行下一个执行上下文 first 函数
  • first 函数执行完毕,对应的函数执行上下文也被推出栈中,然后执行全局上下文
  • 所有代码执行完毕,全局上下文也会被推出栈中,程序结束

参考资料

  1. MDN Web Docs - Execution Context
  2. JavaScript Execution Stack and Call Stack

希望这篇文章对你理解JavaScript中的执行栈和执行上下文有所帮助!