《高效能JavaScript》讀書總結——作用域鏈
資料存取
JS中有如下四種基本資料的存取:
- 字面量:字串、數字、布林值、物件、陣列、函式、正規表示式、null和undefined。
- 本地變數:var/let 定義的資料儲存單元。
- 陣列元素
- 物件成員
通常情況下,訪問速度排序:字面量 > 本地變數 > 陣列元素 > 物件成員。個別瀏覽器的版本,可能有細微差別。
作用域
執行環境/執行期上下文(execution context): 是指當前變數或函式有權訪問的其它資料。每個執行環境都有一個與之關聯的變數物件(variable object, VO),VO是不能直接訪問的,執行環境中定義的所有變數和函式都會儲存在這個物件中,解析器在處理資料的時候就會訪問這個內部物件。
全域性執行環境是最外層的一個執行環境,在web瀏覽器中全域性執行環境是window物件,因此所有全域性變數和函式都是作為window物件的屬性和成員函式建立的。每個函式都有自己的執行環境,當執行流進入一個函式的時候,函式的環境會被推入一個函式棧中,而在函式執行完畢後執行環境出棧並被銷燬,儲存在其中的所有變數和函式定義隨之銷燬,控制權返回到之前的執行環境中,全域性的執行環境在應用程式退出(瀏覽器關閉)才會被銷燬。
每一個JS函式可以看做是Function物件的一個例項,並且含有一個內部屬性[[Scopes]],[[Scopes]]包含了一個函式被建立的作用域中物件的集合。這個集合被稱為作用域鏈,它決定哪些資料能被函式訪問。函式作用域中的每個物件被稱為一個可變物件,每個可變物件都是以“key-value”形式存在。
典型的作用域鏈:
- 函式建立時
此時函式的作用域鏈會壓入第一個作用域物件,即建立此函式的作用域中可訪問的資料物件填充。如下圖所示:
注意:這個作用域物件是可變的,可以理解為這個物件是引用的。
具體物件資訊可以在chrome dev tool中檢視,如下圖:
- 函式執行時
每次執行函式時都會建立一個執行環境,每個執行環境都是獨一無二的,多次呼叫函式就會導致建立多個執行環境。此時會將會將一個被稱為“活動物件”(activation object,AO)的新物件作為第二個作用域物件壓入作用域鏈。如下圖所示:
在函式的執行過程中,每遇到一個變數或者函式,都會在作用域鏈中按照順序進行查詢,直到遍歷所有的作用域,此過程會影響執行效能。
- 閉包時的作用域
如下一段程式碼中,包含了閉包
functionassignEvents(){
var id= "xdi9592";
document.getElementById("save-btn").onclick =function(event){
saveDocument(id);
};
}
- 其他改變作用域的情況
一般作用域鏈的順序是按照呼叫的順序排列的,但是特殊情況下會改變。
- with
執行with語句時,會將with帶入的物件壓入作用域鏈,導致呼叫深度發生變化。
functioninitUI(){
with(document){
var bd= body,
links=getElementsByTagName_r("a"),
i=0,
len= links.length;
while(i<len){
update(links[i++]);
}
getElementById("go-btn").onclick=function(){
start();
};
bd.className ="active";
}
}
- try-catch
類似with,當try塊發生異常時,程式跳轉到catch子句,並且把異常物件壓入作用域首位。catch子句執行完作用域鏈恢復之前的狀態。由於加深了呼叫深度,如果在catch子句執行操作會造成效能問題。可以採用錯誤處理函式的方式,改變作用域鏈的狀態,從而減少呼叫深度。
try{
methodThatMightCauseAnError();
}catch (ex){
handleError(ex);//delegate tohandlermethod
}
識別符號解析的效能
在執行環境的作用域鏈中,一個識別符號的位置越深,他的讀寫速度就越慢,因此函式中讀寫區域性變數是最快的,讀寫全域性變數通常是最慢的。
改進辦法,通過賦值給區域性變數,改變識別符號的深度,從而提高讀寫速度。
for(var i = 0; i < document.getElementsByTagName("a").length; i++){
document.getElementsByTagName("a")[i].class = 'active'
}
//改進後
var list = document.getElementsByTagName("a");
for(var i = 0; i < list.length; i++){
list[i].class = 'active'
}
相關文章
- javascript作用域總結JavaScript
- 紅寶書總結-執行環境、作用域鏈
- JavaScript 作用域 與 作用域鏈JavaScript
- javascript作用域鏈JavaScript
- javascript之作用域與作用域鏈JavaScript
- JavaScript作用域相關的總結JavaScript
- JavaScript之作用域鏈JavaScript
- javascript作用域鏈理解JavaScript
- JS 總結之函式、作用域鏈JS函式
- 深入理解JavaScript作用域和作用域鏈JavaScript
- JavaScript深入之作用域鏈JavaScript
- JavaScript 深入之作用域鏈JavaScript
- 理解JavaScript的作用域鏈JavaScript
- javascript作用域和作用域鏈簡單介紹JavaScript
- 深入理解javascript系列(六):作用域與作用域鏈JavaScript
- JavaScript 變數的作用域鏈JavaScript變數
- 淺談Javascript中的作用域鏈JavaScript
- 《高效能JavaScript》讀書筆記JavaScript筆記
- 【讀書筆記】《高效能JavaScript》筆記JavaScript
- js 作用域和作用域鏈JS
- js的作用域、作用域鏈JS
- 原型、原型鏈、作用域、作用域鏈、閉包原型
- 《高效能 JavaScript》讀書筆記(一)JavaScript筆記
- 我所認識的 JavaScript 作用域鏈和原型鏈JavaScript原型
- js的作用域和作用域鏈JS
- js的作用域與作用域鏈JS
- javaScript 作用域JavaScript
- JavaScript作用域JavaScript
- 為何你始終理解不了JavaScript作用域鏈?JavaScript
- 理解 JavaScript 作用域JavaScript
- ES6 變數作用域總結變數
- 前端入門18-JavaScript進階之作用域鏈前端JavaScript
- JavaScript跨域問題總結JavaScript跨域
- 【前端效能優化】高效能JavaScript讀書筆記前端優化JavaScript筆記
- 高效能JavaScript 重排與重繪 讀書筆記JavaScript筆記
- 學習JavaScript作用域JavaScript
- javascript 詞法作用域JavaScript
- JavaScript 塊級作用域JavaScript