在JavaScript执行上下文栈的具体过程是什么 | 客服服务营销数智化洞察_晓观点
       

在JavaScript执行上下文栈的具体过程是什么

执行上下文(Execution context stack 简称 ECS)就是一个评估和执行JavaScript代码的环境的抽象概念。通俗地说,就是每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。

执行上下文栈是什么

在执行js代码的时候会创建一个全局执行上下文栈(Execution Context Stack)(也称调用栈执行栈), 同时创建一个全局执行上下文,他是一种先进后出的结构, 当有函数执行时会创建一个函数执行上下文, 压入这个栈顶,当执行完成时弹出栈。如图:

在JavaScript执行上下文栈的具体过程是什么

全局执行上下文不会弹出栈,会在关闭浏览器或应用的时候弹出栈。

执行上下文有哪些

js中执行上下文中有三种执行上下文:

  • 全局执行上下文 — 这是默认或者说基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建一个全局的 window对象(浏览器的情况下),并且设置 this 的值等于这个全局对象。一个程序中只会有一个全局执行上下文。
  • 函数执行上下文 — 每当一个函数被调用时, 都会为该函数创建一个新的执行上下文。每个函数都有它自己的执行上下文,不过是在函数被调用时创建的。函数上下文可以有任意多个。每当一个新的执行上下文被创建,它会按定义的顺序(将在后文讨论)执行一系列步骤。
  • Eval 函数执行上下文 — 执行在 eval 函数内部的代码也会有它属于自己的执行上下文, 没什么用,不做解释。 但是他应该是 js 最强大的函数, 他的等同于一个 js 解释器, 他能够解析 js 代码。

执行栈的生命周期

红宝书中对执行栈描述: 执行栈其实也是一个对象,指向计算机中的一块内存,虽然我们拿不到,但是他确实存在。 执行栈的生命周期包含三个阶段: 创建阶段→执行阶段→回收阶段(垃圾回收)

执行上下文的创建类型

执行上下文的创建类型氛围创建时和执行时, 对应创建阶段和执行阶段。

创建时

  • 会生成两个环境, LexicalEnvironment and VariableEnvironment(也是一种词法空间, 但是一般用来记录 var 声明的变量) 词法环境和变量环境都有 3 个组件, 分别是 Environment Record 、 outter (对外部环境的引用)、 thisbinding(this 指向)
  • EnvironmentRecord 又分为 2 种, declare Environment Record 和 Object Environment Record

The environment record is the place where the variable and function declarations are stored inside the lexical environment. (记录了变量和函数声明在词法环境中的存储位置)

  1. declare Environment Record : 顾名思义, 这个用来记录变量和函数的声明
  2. Object Environment Record: 记录除变量以外的声明, 还记录关于浏览器提供给窗口的

全局代码的词法环境包含一个客观的环境记录。除了变量和函数声明之外,对象环境记录还存储一个全局绑定对象(浏览器中的窗口对象)。因此,对于每个绑定对象的属性(在浏览器中,它包含由浏览器提供给窗口对象的属性和方法) ,在记录中创建一个新条目。

The lexical environment for global code contains a objective environment record. Apart from variable and function declarations, the object environment record also stores a global binding object (window object in browsers). So for each of binding object’s property (in case of browsers, it contains properties and methods provided by browser to the window object), a new entry is created in the record.

  • outter 对外部环境引用的记录,我理解就是通过这个找到作用域链, 如果上下文中找不到变量, 会沿着这个outter 指向的上下文空间中去查找, 这也是 js 底层的变量查找机制的原理。
  • thisbinding 对于全局执行上下文这个 this 指向全局对象, 如果是函数执行上下文, 则参考下面这段描述,
  • In the function execution context, the value of this depends on how the function is called. If it is called by an object reference, then the value of this is set to that object, otherwise, the value of this is set to the global object or undefined(in strict mode).
  • 注意的是箭头函数没有自己的 this , 可以简单的理解调用他的对象所指向的 this, 就是箭头函数 this 的指向。

执行时

这个时候所有的变量都被成功分配, 并最终执行代码。

对创建时和执行时通过对一段代码的分析可以更好的理解, 在分析前,要理解一个概念,在代码执行时就会创建一个全局执行上下(一般只有在程序退出的时候销毁), 并压入全局执行栈中。

    let a = 20;
    const b = 30;
    var c;function multiply(e, f) {
     var g = 20;
     return e * f * g;
    }
    c = multiply(20, 30);

全局执行上下文创建时:

GlobalExectionContext = {  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: < uninitialized >,
      b: < uninitialized >,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },  
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

注意: EnvironmentRecord 一般记录 const \ let 还有函数声明,VariableEnvironment 一般记录 var 声明, 使用 const \ let 声明的变量在记录时被标记为 uninitialized(未初始化), 使用 var 声明的变量开始时被标记为 undefined。

如果在 const 和 let 之前使用会报错, reference error, 会有一个暂时性死区(const 或 let 变量执行前的瞬间)如果在这之前使用未定义的变量会报错 。

创建完后会进入执行时, 全局执行上下文执行时:

GlobalExectionContext = {LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: 20,
      b: 30,
      multiply: < func >
    }
    outer: <null>,
    ThisBinding: <Global Object>
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: <null>,
    ThisBinding: <Global Object>
  }
}

在执行的时候, 所有变量都被分配,并最终被执行。

当遇到函数 multiply(20, 30); 时, 会生成一个新的执行上下文(函数执行上下文), 并这个函数执行上下文压入全局执行栈

函数执行上下文, 创建时:

FunctionExectionContext = {
    LexicalEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          // Identifier bindings go here
          Arguments: {0: 20, 1: 30, length: 2},
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>,
      },
      VariableEnvironment: {
        EnvironmentRecord: {
          Type: "Declarative",
          // Identifier bindings go here
          g: undefined
        },
        outer: <GlobalLexicalEnvironment>,
        ThisBinding: <Global Object or undefined>
      }
}

可以观察到, 函数执行上下文中的环境记录包含一个 arguments 对象, 该对象包含传递给函数的索引和参数之间的映射,以及传递给函数的参数的长度(数目)。

函数创建上下文, 执行时:

FunctionExectionContext = {LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

当这个函数执行上下文完成后,返回的值存储在 c 中。因此,全局词汇环境得到了更新。然后,全局代码完成,程序完成。

结语

执行上下文栈是JavaScript代码执行过程中的核心组成部分,它管理着全局和函数执行上下文的创建、执行和回收。通过深入理解执行上下文栈的工作原理,我们可以更好地掌握JavaScript中的变量作用域、this值的绑定以及函数的调用机制。这不仅有助于我们编写更高效、更可靠的JavaScript代码,还能让我们在面对复杂问题时,能够迅速定位并解决问题。希望本文能够帮助读者加深对执行上下文栈的理解,并在实际开发中灵活运用这一知识。更多关于执行上下文栈的详细信息和示例,请访问掘金链接:https://juejin.cn/post/7408723089612537906

延展阅读:

淘宝拼多多香港包邮政策有什么区别?对商家业绩增长有什么帮助?

大促期间客服容易漏回消息?电商商家怎么用智能工具高效提升客服响应速度?

智能客服回复不准确影响客户满意度?电商商家怎么通过数据分析快速提高其应答水平

咨询方案 获取更多方案详情                        
(0)
研发专家-luck_luo研发专家-luck_luo
上一篇 2024年11月1日 下午7:03
下一篇 2024年11月3日 上午10:20

相关推荐