执行栈与作用域链

93 阅读3分钟

执行上下文的概念

执行上下文是JavaScript执行一段代码时,为其划分的基础运行环境,此段上下文决定了它们可以访问那些数据。其中的数据包括了变量环境,语法环境,this指向,外部环境等等。


执行上下文的类型

执行上下文分为三种类型:

  1. 全局执行上下文:最外层的上下文,也就是常说的Windows对象,通常是在整个JavaScript文件运行时被创建、在浏览器或者网页退出后被销毁。
  2. 函数执行上下文:就是在一段函数生成时,都会为该函数创建一个新的上下文,每次函数被调用时都会生成一个新的执行上下文。
  3. Eval函数执行上下文:执行在 eval 函数内部的代码也会有它属于自己的执行上下文。(了解即可)

上下文所包含的内容

1.执行栈

定义: 执行栈也叫做调用栈或者执行上下文栈,是JavaScript中的一种数据结构,用于存储在程序执行期间创建的各种执行上下文。

因为 JS 执行中最先进入全局环境,所以最开始处于栈底的是全局环境的执行上下文 。当一个函数被调用时,会创建一个新的执行上下文,并被推入调用栈的顶部。而当函数执行完毕后,对应的执行上下文则会从调用栈中弹出

这样,调用栈以"后进先出"的顺序管理着函数的执行顺序。调用栈的大小是有限的,如果函数调用过多,可能会导致调用栈溢出。

function foo() {
  function bar() {
    var str = 'string'
    console.log('I am bar')
  }
  bar()
}
​
foo()

2.作用域链

定义: 作用域决定了代码在当前执行上下文中可访问的变量和函数,作用域链则是在这个范围中,函数进行所需变量查找时所访问的作用域顺序。当函数被调用时,就会创建一个新的执行上下文,这个执行上下文包含了当前函数的作用域链。

当在JavaScript中使用一个变量的时候,JavaScript引擎会尝试在当前作用域下去寻找变量,若是在当前变量对象中未找到标识符,就会继续在外部环境的引用指向的变量对象中查找。这样依次往外层的执行上下文中查找,以此类推直到找到变量或是直到找到全局执行上下文。

举个简单例子

var a = 10;
​
function outerFunction() {
  var b = 20;
​
  function innerFunction() {
    var c = 30;
    console.log(a + b + c);
  }
​
  innerFunction();
}
​
outerFunction();

innerFunction()被调用执行时,它的作用域链为{c > b > a > global},

结合调用栈的上下文操作,上述作用域的栈运行过程如下:

image-20240311204752028.png

从innerFunction()开始到outerFunction()再到全局执行上下文,读取顺序跟执行栈的顺序有关。

如果说函数执行上下文是为函数的运行划分出基本的访问范围;作用域链则是在这个范围中,函数查找变量所访问的作用域顺序。

执行栈与作用域链的查找顺序息息相关,函数的作用域链的查找顺序是按照执行栈中的执行上下文顺序来进行的。当 JavaScript 引擎在执行上下文中查找变量时,它会首先在当前执行上下文的变量对象中查找,如果没有找到,就会沿着作用域链向父级执行上下文查找,直到全局执行上下文。由于执行栈管理着函数的执行顺序,所以作用域链的查找顺序受限于执行栈中执行上下文的顺序。执行栈的上下文顺序直接影响了函数作用域链的查找过程。