關鍵字:標識符、執行上下文、作用域、作用域鏈、變數物件、活動物件理論知識
理解JavaScript如何管理作用域和作用域鏈很重要。因為在作用域鏈中要尋找的變數物件的數量直接影響標識符解析的效能。標識符在作用域鏈中的位置越深,尋找和存取它所需的時間越長;如果作用域管理不當,就會對腳本的執行時間帶來負面影響。
當執行JavaScript程式碼時,JavaScript引擎會建立一個執行上下文(Execution Context)。執行上下文(有時稱為作用域)設定了程式碼執行時所處的環境。 JavaScript引擎會在頁面載入後建立一個全域的執行上下文,然後每執行一個函數時都會建立一個對應的執行上下文,最終建立一個執行上下文的堆疊,目前起作用的執行上下文在堆疊的最頂端。
每個執行情境都有一個與之關聯的作用域鏈,用於解析標識符。作用域鏈包含一個或多個變數物件,這些物件定義了執行上下文作用域內的識別碼。全域執行上下文的作用域鏈中只有一個變數對象,它定義了JavaScript中所有可用的全域變數和函數。當函數被創建(不是執行)時,JavaScript引擎會把創建時執行上下文的作用域鏈賦給函數的內部屬性[[Scope]]。然後,當函數被執行時,JavaScript引擎會建立一個活動物件(Activetion Object),並在初始化時給this、arguments、命名參數和該函數的所有局部變數賦值。活動物件會出現在執行上下文作用域鏈的頂端,緊接著的是函數[[scope]]屬性中的物件。
在執行程式碼時,JavaScript引擎透過搜尋執行上下文的作用域鏈來解析諸如變數和函數名稱這樣的識別碼。解析標識符的過程從作用域的頂端開始,依照自上而下的順序進行。
驗證理論function add(num1, num2) {
return num1 num2;
}
當這段程式碼執行開始時,add函數擁有一個僅包含全域變數物件的[[scope]]屬性。如下圖:
執行add函數時,JavaScript引擎會建立一個新的執行上下文和一個包含this、arguments、num1、num2的活動對象,並將活動對象加入到作用域鏈中。在add()函數內部執行時,JavaScript引擎需要解析函數裡的num1和num2標識符。 var total = add(5, 10);
解析過程是從作用域鏈中的第一個物件開始,這個物件就是包含該函數局部變數的活動物件。如果在該物件中沒有找到標識符,就會繼續在作用域鏈中下一個物件裡尋找標識符。一旦找到標識符,查找就結束。
高效率的資料存取局部變數是JavaScript中讀寫最快的識別碼。
一個好的經驗:任何非局部變數在函數中的使用超過一次時,都應該儲存為局部變數。
對於數組和對象,始終將那些需要頻繁訪問的值儲存到局部變數中。
實際上每次訪問HTMLCollection物件屬性,都會對DOM文件進行動態查詢。
如果需要對HTMLCollection物件的成員重複訪問,高效的方式是將它們複製到陣列裡。