JavaScript代码在执行时会进入一个运行环境,这是我们都知道的。这种运行环境我们也叫做执行上下文(Execution Context)。
javascript中常见的运行环境有三种:
1、全局环境:代码运行首先进入的就是全局环境。
2、函数环境:当函数运行时,就会进入当前函数中执行代码。
3、eval环境:不做解释,可以参考《你不知道javascript上》。
因此可以预见的是,在一段javascript代码运行时,必定会有不少运行环境的出现。
javascript引擎会以栈的方式来处理这些运行环境,这个栈,就是call stack(函数调用栈)。call stack规定javascript代码执行的顺序。栈底永远都是全局上下文(全局环境),栈顶则是当前正在执行的上下文。
当代码遇到以上几种情况,都会生产执行上下文并进入call stack。处于栈顶的执行上下文执行完毕后会自动退出call stack。(这也符合了我们所说的栈的“兵乓球盒模型”)。
为了清晰的看到整个代码执行的过程,我们通过几个实例来了解call stack的规则。
为了方便学习js核心,推荐这个工具:latentflip.com/loupe。简直六的不行!
3.1 实例1
var color = 'blue';
function changeColor() {
var anotherColor = 'red';
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColors();
}
changeColor();
复制代码
在我们开始了解之前,我们应该自己心里先把流程跑一遍。
好了,现在开始
第一步全局上下文入栈,并一直存于栈底。(由于loupe工具没有显示全局环境,所以这里就不上图了。
第二步,全局上下文入栈后,从可执行代码开始执行(在代码执行之前还有些活动,我稍后系列中会做笔记),直到遇到了changeColors(),这句代码激活了函数changeColors,从而创建了自己的执行上下文。因而此时是changeColorsEC的上下文入栈。如下图所示:
第三步,changeColorsEC的上下文入栈后,开始执行可执行的代码,当遇到swapColors()这句代码时激活了swapColors的执行上下文。因此第三步就是changeColorsEC的上下文入栈。如下图所示:
第四步,在swapColors的可执行代码中,没有其他能生成执行上下文的情况,因此这段代码顺利结束自己,他会从call stack中弹出。
第五步,在swapColors的执行上下问弹出后,在changeColors执行上下文中,继续执行可执行的代码,没有在遇到其它的执行上下文,顺利弹出。这样整个,call stack中就只剩下全局上下文了。
最后,关闭浏览器窗口,全局上下文弹出栈。
3.2 实例2
function f1() {
var n = 999;
function f2() {
alert(n);
}
return f2;
}
var result = f1();
result();
复制代码
这是一个简单的闭包实例,我们只需根据“函数执行时,执行上下文被激活”。这一原则继续在我们心里走一遍代码执行过程。
第一步仍然是全局上下文入栈。
第二步,执行可执行的代码,当遇到f1()时,f1的执行上下被激活,并入栈。
第三步,在f1中执行可执行的代码,没有可执行的上下文,弹出栈来。
第四步,继续在全局上下文中,执行可执行的代码,这个时候遇到了result(),result()会创建一个的新的上下文(被激活),因此这时result的上下文入栈。
第五步,这个result()其实就是在f1中声明的函数f2,因此这个时候会执行f2中的代码。由于在f2中没有产生新的上下文,因此执行完毕后直接出栈。
3.3 生命周期
我们知道,当一个函数调用时,一个新的执行上下会被创建。一个执行上下文的生命周期大致可以分为两个阶段:创建阶段和执行阶段
创建阶段
在这个阶段,执行上下文会分别创建变量对象,确认作用域链,以及确定this的指向。
执行阶段
创建阶段之后,就开始执行代码,这个时候会完成变量赋值、函数引用、以及执行其它可执行的代码。
从执行上下文的生命周期可以看到它的重要性,其中涉及了变量对象、作用域链、this等许多重要但并不容易搞清楚的概念,这些概念有助于我们真正理解javascript代码的运行机制。我会在之后的系列中持续上传我的学习笔记。@阳波大神
记住:执行上下文(全局、函数)、函数激活会干嘛?、执行上下文的生命周期