數(shù)據(jù)存取
JS中有如下四種基本數(shù)據(jù)的存燃癖椤:
- 字面量:字符串锌订、數(shù)字、布爾值画株、對(duì)象瀑志、數(shù)組涩搓、函數(shù)、正則表達(dá)式劈猪、null和undefined。
- 本地變量:var/let 定義的數(shù)據(jù)存儲(chǔ)單元良拼。
- 數(shù)組元素
- 對(duì)象成員
通常情況下战得,訪問速度排序:字面量 > 本地變量 > 數(shù)組元素 > 對(duì)象成員。個(gè)別瀏覽器的版本庸推,可能有細(xì)微差別常侦。
作用域
執(zhí)行環(huán)境/運(yùn)行期上下文(execution context): 是指當(dāng)前變量或函數(shù)有權(quán)訪問的其它數(shù)據(jù)。每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象(variable object, VO)贬媒,VO是不能直接訪問的聋亡,執(zhí)行環(huán)境中定義的所有變量和函數(shù)都會(huì)保存在這個(gè)對(duì)象中,解析器在處理數(shù)據(jù)的時(shí)候就會(huì)訪問這個(gè)內(nèi)部對(duì)象际乘。
全局執(zhí)行環(huán)境是最外層的一個(gè)執(zhí)行環(huán)境坡倔,在web瀏覽器中全局執(zhí)行環(huán)境是window對(duì)象,因此所有全局變量和函數(shù)都是作為window對(duì)象的屬性和成員函數(shù)創(chuàng)建的脖含。每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境罪塔,當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)的時(shí)候,函數(shù)的環(huán)境會(huì)被推入一個(gè)函數(shù)棧中养葵,而在函數(shù)執(zhí)行完畢后執(zhí)行環(huán)境出棧并被銷毀征堪,保存在其中的所有變量和函數(shù)定義隨之銷毀,控制權(quán)返回到之前的執(zhí)行環(huán)境中关拒,全局的執(zhí)行環(huán)境在應(yīng)用程序退出(瀏覽器關(guān)閉)才會(huì)被銷毀佃蚜。
每一個(gè)JS函數(shù)可以看做是Function對(duì)象的一個(gè)實(shí)例,并且含有一個(gè)內(nèi)部屬性[[Scopes]],[[Scopes]]包含了一個(gè)函數(shù)被創(chuàng)建的作用域中對(duì)象的集合着绊。這個(gè)集合被稱為作用域鏈谐算,它決定哪些數(shù)據(jù)能被函數(shù)訪問。函數(shù)作用域中的每個(gè)對(duì)象被稱為一個(gè)可變對(duì)象畔柔,每個(gè)可變對(duì)象都是以“key-value”形式存在氯夷。
典型的作用域鏈:
- 函數(shù)創(chuàng)建時(shí)
此時(shí)函數(shù)的作用域鏈會(huì)壓入第一個(gè)作用域?qū)ο螅磩?chuàng)建此函數(shù)的作用域中可訪問的數(shù)據(jù)對(duì)象填充靶擦。如下圖所示:
注意:這個(gè)作用域?qū)ο笫强勺兊娜迹梢岳斫鉃檫@個(gè)對(duì)象是引用的。
具體對(duì)象信息可以在chrome dev tool中查看玄捕,如下圖:
- 函數(shù)執(zhí)行時(shí)
每次執(zhí)行函數(shù)時(shí)都會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境踩蔚,每個(gè)執(zhí)行環(huán)境都是獨(dú)一無(wú)二的,多次調(diào)用函數(shù)就會(huì)導(dǎo)致創(chuàng)建多個(gè)執(zhí)行環(huán)境枚粘。此時(shí)會(huì)將會(huì)將一個(gè)被稱為“活動(dòng)對(duì)象”(activation object,AO)的新對(duì)象作為第二個(gè)作用域?qū)ο髩喝胱饔糜蜴溝诿觥H缦聢D所示:
在函數(shù)的執(zhí)行過程中,每遇到一個(gè)變量或者函數(shù),都會(huì)在作用域鏈中按照順序進(jìn)行查找福也,直到遍歷所有的作用域局骤,此過程會(huì)影響運(yùn)行性能。
- 閉包時(shí)的作用域
如下一段代碼中暴凑,包含了閉包
functionassignEvents(){
var id= "xdi9592";
document.getElementById("save-btn").onclick =function(event){
saveDocument(id);
};
}
- 其他改變作用域的情況
一般作用域鏈的順序是按照調(diào)用的順序排列的峦甩,但是特殊情況下會(huì)改變。
- with
執(zhí)行with語(yǔ)句時(shí)现喳,會(huì)將with帶入的對(duì)象壓入作用域鏈凯傲,導(dǎo)致調(diào)用深度發(fā)生變化。
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嗦篱,當(dāng)try塊發(fā)生異常時(shí)冰单,程序跳轉(zhuǎn)到catch子句,并且把異常對(duì)象壓入作用域首位灸促。catch子句執(zhí)行完作用域鏈恢復(fù)之前的狀態(tài)诫欠。由于加深了調(diào)用深度,如果在catch子句執(zhí)行操作會(huì)造成性能問題腿宰∨凰撸可以采用錯(cuò)誤處理函數(shù)的方式瞳别,改變作用域鏈的狀態(tài)揖盘,從而減少調(diào)用深度。
try{
methodThatMightCauseAnError();
}catch (ex){
handleError(ex);//delegate tohandlermethod
}
標(biāo)識(shí)符解析的性能
在執(zhí)行環(huán)境的作用域鏈中炮障,一個(gè)標(biāo)識(shí)符的位置越深椿每,他的讀寫速度就越慢伊者,因此函數(shù)中讀寫局部變量是最快的,讀寫全局變量通常是最慢的间护。
改進(jìn)辦法亦渗,通過賦值給局部變量,改變標(biāo)識(shí)符的深度汁尺,從而提高讀寫速度法精。
for(var i = 0; i < document.getElementsByTagName("a").length; i++){
document.getElementsByTagName("a")[i].class = 'active'
}
//改進(jìn)后
var list = document.getElementsByTagName("a");
for(var i = 0; i < list.length; i++){
list[i].class = 'active'
}