执行上下文与执行栈

当函数被调用的时候会创建一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。

  • 全局环境:JavaScript代码运行起来会首先进入该环境

  • 函数环境:当函数被调用执行时,会进入当前函数中执行代码

  • eval

因此在一个JavaScript程序中,必定会产生多个执行上下文,JavaScript引擎会以堆栈的方式来处理它们,这个堆栈,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。

当代码在执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。为了更加清晰的理解这个过程,根据下面的例子,结合图示给大家展示。

var color = 'blue';

function changeColor() {

    var anotherColor = 'red';

    function swapColors() {

        var tempColor = anotherColor;

        anotherColor = color;

        color = tempColor;

    }

    swapColors();

}

changeColor();
console.log(color)   // red
复制代码

我们用ECStack来表示处理执行上下文组的堆栈。第一步,首先是全局上下文入栈。

640.png

全局上下文入栈之后,其中的可执行代码开始执行,直到遇到了changeColor(),调用了changeColor这个函数然后开始创建它自己的执行上下文,因此第二步就是changeColor的执行上下文入栈。

640 (1).png

changeColor的上下文入栈之后,控制器开始执行其中的可执行代码,当遇到swapColors()之后又产生了一个执行上下文。因此第三步是swapColors的执行上下文入栈。

640.webp

在swapColors的可执行代码中,再没有遇到其他能生成执行上下文的情况(即没有新的函数调用),因此这段代码顺利执行完毕,swapColors的上下文从栈中弹出。

640 (2).png

swapColors的执行上下文弹出之后,继续执行changeColor的可执行代码,也没有再遇到其他执行上下文,顺利执行完毕之后弹出。这样,ECStack中就只身下全局上下文了。

640 (3).png

整个过程

640 (1).webp

函数执行上下文的创建过程

  1. 在调用函数,准备执行函数函数体之前,创建对应的函数执行上下文对象
  2. 对函数体内的数据预处理
    • var声明的变量和形参,值为undifined,成为该执行上下文的属性
    • 形参与实参统一
    • 函数声明,添加为该执行上下文的方法
    • this赋值(调用该函数的对象)
  3. 执行函数体代码

当函数被调用,该函数就会被压入执行栈中

全局执行上下文创建过程

  1. 在执行代码前,将window对象确定为全局执行上下文对象
  2. 对全局数据进行预处理
    • var声明的全局变量,值为undifined,作为window属性
    • function声明的全局函数,作为window的方法
    • this指向window
  3. 开始执行全局上下文
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享