Js系列三:執行上下文
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程式碼的執行機制。
...................................................................
下一章我們將來具體講下變數物件