深入理解JavaScript系列(2):执行上下文栈
JS 是否是顺序执行?
JavaScript 代码的执行顺序,在写过该语言的人眼中,都会认为是顺序执行的。
1 | var fn = function () { |
完美的顺序执行,但是我们稍微修改一下呢?
1 | function fn() { |
打印结果真的是出人意料啊,两个都为 second function
。这又是为什么呢?
因为我们的 JavaScript
引擎执行代码是通过一段一段的执行,而不是一行一行的执行。所以当执行一段代码时,就会进入一个准备工作,比如变量提升或函数提升。
现在我们了解到了,执行方式,那我们再来看看,JS
是怎么一段一段的执行的。
执行上下文
我们先了解一下执行上下文,执行上下文就是当前 JavaScript 代码被解析和执行时所在环境的抽象概念,JavaScript 中运行任何的代码都是在执行上下文中运行。
JavaScript 中的运行环境包括三种情况:
- 全局环境:JavaScript 代码运行首先会进入该环境
- 函数环境:当函数被调用执行时,就会进入该环境
- eval:运行在 eval 函数中的代码创建的自己的执行上下文(不建议使用,基本上算作是一个作废的东西)
举一个小例子,当执行一个函数时,就会进行准备工作,而这个准备工作,专业一点的说法就是执行上下文。
什么是执行上下文栈?
那么函数多了,如何来管理这么多执行上下文呢?
所以 JavaScript 引擎创建了执行上下文栈来管理执行上下文。
我们使用一个 ECStack
数组,作为执行上下文栈的行为模拟工具。
首先,当 JavaScript
开始解析执行代码时,先遇到一个全局代码,所以在初始化我们的执行栈时,就会向执行上下文栈压入一个全局执行栈(globalContext
)。
并且只有整个程序执行结束时,ECStack
才会被清空,所以在程序结束之前,globalContext
会一直存在于 ECStack
的最底部。
1 | ECStack = []; // 创建 |
我们写一段代码,来测试我们的执行栈。
1 | function fn1() { |
当执行函数时,就会创建一个执行上下文,并且压入栈,执行完毕,就会从栈中弹出。我们用数组来模拟栈,所以是先进后出。
所以我们来看看时怎么执行栈的吧:
1 | // 一开始执行时,栈中有全局执行栈 |
深入执行上下文栈,就介绍到这里了。