關鍵詞:
執行上下文、詞法環境、變量環境、this、執行上下文棧、變量對象、做用域鏈javascript
執行上下文定義了變量或函數有權訪問的其餘數據,決定了他們各自的行爲。當javascript代碼執行一段可執行代碼時,會建立對應的執行上下文; 代碼所有執行完後,該執行上下文也會被銷燬,保存在其中的變量和函數定義也隨之被銷燬。執行上下文會管理代碼執行過程當中使用的內存。前端
執行上下文分3種:java
javascript引擎建立執行上下文有兩個階段:web
在全局執行上下文中,this指向全局對象(瀏覽器中指window對象);
在函數執行上下文中,this的值取決於函數是如何並調用的。若是函數被一個引用對象調用,那麼this會被設置成這個對象,不然this會被設置爲window或undefined(嚴格模式下)瀏覽器
var obj = {
getThis: function(){
return this
}
}
obj.getThis(); // obj
var fn = obj.getThis
fn(); // window
複製代碼
詞法環境是一種規範類型,基於ECMAScript代碼的詞法嵌套結構來定義「標識符」和具體函數和變量的關係。存儲let,const 定義的函數聲明和變量綁定bash
一個詞法環境由一個環境記錄器和一個(可能存在的)對外部詞法環境的引用組成。函數
變量環境其實也是一個詞法環境,用來存儲變量聲明語句在執行上下文中建立的綁定關係,即,存儲var聲明的變量的綁定ui
在建立階段,let、const定義的變量變量沒有關聯任何值,可是var聲明的變量會被設置爲undefined,因此var變量在聲明以前訪問值爲undefined,但不會報錯,即變量聲明提高。let、const變量聲明前訪問會致使引用錯誤。this
執行階段完成對全部變量的分配,並執行代碼。spa
javascript引擎建立執行上下文棧管理執行代碼是建立的全部執行上下文。
當JavaScript腳本第一次執行代碼時,會建立一個全局執行上下文,並壓入執行棧;以後每次調用函數時,會爲該函數建立一個函數執行上下文並壓入棧,當函數執行結束,對應當執行上下文從棧中彈出。
下面兩段代碼的執行結果同樣"local",可是執行上下文棧的變化不一樣。
var scope = "global";
function checkScope(){
var scope = "local";
function fn(){
return scope;
}
return fn();
}
checkScope();
// 方法執行時 執行上下文棧的變化以下
ESCStack.push(<checkScope> function-Context)
ESCStack.push(<fn> function-Context)
ESCStack.pop()
ESCStack.pop()
複製代碼
var scope = "global";
function checkScope(){
var scope = "local";
function fn(){
return scope;
}
return fn;
}
checkScope()();
// 方法執行時 執行上下文棧的變化以下
ESCStack.push(<checkScope> function-Context)
ESCStack.pop()
ESCStack.push(<fn> function-Context)
ESCStack.pop()
複製代碼
JavaScript函數執行時用到做用域鏈,做用域鏈是在函數定義時建立的。
- 變量對象 Variable Object
- 做用域鏈 Scope Chain
- this
變量對象是與執行上下文相關的數據做用域,存儲在上下文中定義的變量和函數聲明。
全局執行上下文中的變量對象就是全局對象,在瀏覽器中全局對象就是window對象。
在函數執行上下文中,用**活動對象(Activation-Object)**表示比變量對象。互動對象在進入函數執行上下文時被建立,它經過函數的arguments屬性初始化。
變量對象包括函數的全部形參、函數聲明(function)、變量聲明(var)。若是變量名稱和已經聲明的形參或函數名稱相同,變量聲明不會干擾已經存在的這類屬性。
做用域鏈保證對執行上下文有權訪問的全部變量和函數的有序訪問。
做用域的前端,始終是當前執行代碼所在執行環境的變量對象;做用域的最後一個對象,始終是全局執行上下文的變量對象。
標識符解析是從做用域鏈的前端開始,逐層向上搜索標識符的過程。