什麼是執行上下文?
個人理解:當前JavaScript程式碼解析和執行時候的環境就是執行上下文
執行上下文共有三種型別:
全域性執行上下文:只有一個,JavaScript程式碼載入的時候就會進入這個環境,然後建立瀏覽器中的全域性物件(window),全域性上下文的this指向window
函式執行上下文:有很多個,每個函式被呼叫的時候都會建立一個該函式的執行上下文
Eval執行上下文:Eval函式執行時的上下文
因為Eval函式存在效能及安全問題,所以一般不建議使用,本文主要討論全域性執行上下文及函式執行上下文
執行上下文的建立分為兩個階段:
1. 建立階段
2. 執行階段
建立階段:確定this及作用域鏈,宣告函式並初始化,宣告變數並賦予預設值undefined,建立arguments物件
執行階段:變數賦值並執行其它程式碼
注:上述建立階段變數宣告指var宣告的變數,所以可以在變數宣告前訪問該變數(undefined),
如果是let或者const宣告的變數,只有執行了let活const程式碼後該變數才可以訪問,這是因為
let或const宣告的變數,不存在變數提升。而且要求必須 等let宣告語句執行完之後,變數才能使用,不然會報Uncaught ReferenceError錯誤。ES6 明確規定,如果區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。總之,在程式碼塊內,使用let或const命令宣告變數之前,該變數都是不可用的。
看木易楊的文章講建立階段還會分為
1. 確定this,也被稱為This Binding
2. 詞法環境元件建立
3. 變數環境元件建立
對這一塊的理解還不夠,故本文不做擴充,有興趣的朋友可以檢視原文連結:
github.com/yygmind/blo…或自行查閱相關資料。
什麼是執行棧?
個人理解:執行棧就是一個儲存JavaScript程式碼執行上下文的棧,既然是棧,所以具有 LIFO(後進先出)結構,也就是JavaScript程式碼載入的時候,全域性執行上下文入棧,然後執行函式時對應的函式執行山下文入棧,函式執行結束,該函式執行上下文出棧,最後頁面關閉的時候,全域性執行上下文出棧。例如下程式碼:
function foo(){
function bar(){
console.log('bar');
};
bar();
}
foo();
複製程式碼
首先全域性上下文入棧
foo執行上下文入棧
bar執行上下文入棧
然後就是bar執行完畢,bar執行上下文出棧,foo執行上下文出棧,頁面關閉,全域性執行上下文出棧。
理解了執行棧,我們來看一個小例子:
function printN1(n){
for(let i = 1;i<=n;i++){
console.log(i);
}
}
printN1(10);
function printN2(n){
if(n){
console.log(n);
n -= 1;
printN2(n);
}
}
printN2(10);
複製程式碼
上面兩個程式碼,都是列印<=n的正整數,如果忽略列印順序的問題,哪一種實現更好呢,或者說差的那一種有什麼問題呢?如果n比較小的時候你沒有感覺到什麼差異,那把n改為10000呢?
如果有錯誤或者不嚴謹的地方,請給予指正,十分感謝!