Js代码在运行的时候会进入一个特定的环境中,这个环境被称为执行上下文。在Js中运行环境主要包括以下三种情况
(1)全局环境既Js代码运行时首先进入的环境。
(2)函数环境:函数运行时会进入当前函数的环境执行代码。
(3)eval环境:此不推荐使用。
由此我们知道在Js程序执行过程中必然会出现多个执行环境(执行上下文)。Js引擎以函数调用栈的方式来处理,函数调用栈规定了Js代码的执行顺序。栈底永远都是全局上下文,栈顶则是当前正在执行的上下文(具体看Js系列一)。当执行中遇到以上情况时,JS会创建一个执行上下文并放入函数调用栈中,处于栈顶的上下文执行完毕后会自动出栈。
为了更好的理解这个过程我们通过几个实列来理解函数调用栈的执行规则。
一,实例一。
//demo1
var color='blue';
function changeColor(){
var anotherColor = 'red';
function swapColors(){
var tempColor= anotherColor;
anotherColor = color;
color= tempColor;
}
swapColors();
}
changeColor();
我们用ECStack来表示处理执行上下文的堆栈。
第一步:全局上下文入栈
ECStack | |
---|---|
Global Context |
第二步:全局上下文入栈之后,从可执行代码开始执行,直到遇到changeColor(), 这条语句代码激活了changeColor,从而创建了changeColor自己的执行上下文,因此changeColor的ECStack上下文入栈。
ECStack |
changeColor EC |
Global Context |
第三步:changeColor EC的上下文执行之后,开始执行其中可执行的代码,直到遇到swapColors()这句话之后激活了swapColors的执行上下文,因此swapColors的ECStack上下文入栈。
ECStack |
swapColors EC |
changeColor EC |
Global Context |
第四步:在swapColors的可执行代码当中,没有其他能生成执行上下文的情况,因此这段代码执行完毕,swapColors的上下文从栈中弹出。
ECStack |
changeColor EC |
Global Context |
第五步:swapColors的执行上下文弹出之后,继续执行changeColor的可执行上下文,没有在遇到其他可生成新的执行上下文的情况,顺利执行完毕之后弹出。
ECStack |
Global Context |
第六步:全局上下文在浏览器关闭之后出栈。
注意:函数的执行过程在遇到return之后会直接终止可执行代码的执行,因此会直接将当前的执行上下文弹出栈。
二,实列2
//demo2
functionf1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();//999
这是一个简单的闭包的列子,但具有一定的迷惑性。但是我们只需要根据"函数执行时才会创建执行上下文"这一原则来理解,那么这段代码执行时的函数调用栈顺序就比较清晰了。
第一步:全局上下文先入栈。
ECStack |
Global Context |
第二步:全局上下文在执行代码的过程当中遇到了f1()函数,执行var result=f1();因此f1()函数会创建对应的执行上下文并入栈。
ECStack |
f1 EC |
Global Context |
第三步:在执行f1()的过程当中,虽然申明了一个函数f2,但是并没有执行任何函数,因此也就不会产生执行上下文,代码执行结束之后,f1自然会出栈。
f1 EC出栈
ECStack |
Global Context |
第四不:f1函数出栈之后,继续执行全局上下文代码,这个时候遇到了result(),result()创建一个新的执行上下文并入栈。
result EC入栈
ECStack |
result EC |
Global Context |
第五步:这个 result()其实就是f1()中申明的函数f2,因此这个时候回执行f2中的代码,由于在f2中没有产生新的执行上下文,因此执行完毕之后直接出栈。
result EC出栈
ECStack |
Global Context |
三,生命周期
我们知道,当一个函数被调用时,一个新的执行上下文会被创建。一个执行上下文的生命周期大致可以分为两个阶段创建阶段和执行阶段。
创建阶段:
在这个阶段,执行上下文分别创建变量对象,确认作用域链,以及确定this的指向。
执行阶段:
创建阶段之后,就开始执行代码,这个时候会完成变量的赋值,函数引用,以及执行其他可执行的代码。
创建:{生成变量对象,确定作用域链,确定this指向 }--->执行:{变量赋值,函数引用,执行其他代码}--->执行完毕后等待回收->
我们从执行上下文的生命周期中可以看到他的重要性,其中涉及了变量对象,作用域链,this指向等许多重要但并不太容易搞清楚的概念,而理解这这些概念有助于我们真正理解Js代码的运行机制。
...................................................................
下一章我们将来具体讲下变量对象