一、引
在看面试题的时候,看到这个东西,所以学习下到底是什么东西。
二、啥是执行上下文
当 JavaScript 代码运行的时候,确定它运行所在的环境是非常重要的。运行环境由下面三种不同的代码类型确定
1.全局代码(Global Code):代码首次执行时候的默认环境
2.函数代码(Function Code):每当执行流程进入到一个函数体内部的时候
3.Eval代码(Eval Code):当eval函数内部的文本执行的时候
同样就会有三种对应的环境
1.全局环境:JavaScript代码运行起来会首先进入该环境
2.函数环境:当函数被调用执行时,会进入当前函数中执行代码
3.Eval
在 JavaScript 中执行代码,都会先进去一个执行上下文,然后再根据上下文中的代码再进入不同的其他上下文,因此在一个 JavaScript 程序中,必定会产生多个执行上下文,JavaScript 引擎会以堆栈的方式来处理它们,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。
大概就是,最开始运行代码,把全局上下文压栈,然后遇到函数上下文或者 Eval 就再次压栈,执行结束就出栈,最后全局上下文出栈,代码运行结束。
看个例子
var a = 100;
function changea() {
var b = 60;
function swap() {
var t = a;
a = b;
b = t;
}
swap();
}
changea();
来看看函数调用栈的情况
全局上下文入栈
┌───────────────────────────┐
│ ECStack │
│ │
│ │
│ │
│ │
│ │
│ │
│───────────────────────────│
│ Global Context │
└───────────────────────────┘
全局上下文入栈之后,其中的可执行代码开始执行,直到遇到了 changea()
,这一句激活函数 changea()
创建它自己的执行上下文,因此第二步就是 changea()
的执行上下文入栈。
changea上下文入栈
┌───────────────────────────┐
│ ECStack │
│ │
│ │
│ │
│ │
│───────────────────────────│
│ changea EC │
│───────────────────────────│
│ Global Context │
└───────────────────────────┘
changeColor()
的上下文入栈之后,控制器开始执行其中的可执行代码,遇到 swap()
之后又激活了一个执行上下文。因此第三步是 swap()
的执行上下文入栈。
swap上下文入栈
┌───────────────────────────┐
│ ECStack │
│ │
│ │
│───────────────────────────│
│ swap EC │
│───────────────────────────│
│ changea EC │
│───────────────────────────│
│ Global Context │
└───────────────────────────┘
在 swap()
的可执行代码中,再没有遇到其他能生成执行上下文的情况,因此这段代码顺利执行完毕,swap()
的上下文从栈中弹出。
swap上下文出栈
┌───────────────────────────┐
│ ECStack │
│ │
│ │
│ │
│ │
│───────────────────────────│
│ changea EC │
│───────────────────────────│
│ Global Context │
└───────────────────────────┘
swap()
的执行上下文弹出之后,继续执行 changea()
的可执行代码,也没有再遇到其他执行上下文,顺利执行完毕之后弹出。这样,ECStack 中就只身下全局上下文了。
changea上下文出栈
┌───────────────────────────┐
│ ECStack │
│ │
│ │
│ │
│ │
│ │
│ │
│───────────────────────────│
│ Global Context │
└───────────────────────────┘
全局上下文在浏览器窗口关闭后出栈。