2.1作用域增長
with和try-catch語句可以在作用域鏈的前端添加新的變量對象姐叁。當(dāng)執(zhí)行流進(jìn)入with或者try-catch語句時,系統(tǒng)會在作用域鏈頂端增加臨時的變量對象洗显,直至try-catch語句或with語句執(zhí)行結(jié)束外潜,系統(tǒng)銷毀作用域鏈頂端的臨時變量對象。
對于with語句墙懂,系統(tǒng)會將with指定的對象加入頂端的臨時變量對象中橡卤。
這個增加的變量對象擁有所有l(wèi)ocation對象中包含的屬性和方法损搬,其實(shí)在對url進(jìn)行命名時碧库,系統(tǒng)首先從with變量對象中找到了location.href,又在外層的buildUrl變量對象里找到了qs的值巧勤,將二者相加嵌灰。這就是標(biāo)準(zhǔn)的標(biāo)識符解析過程。
2.2沒有塊級作用域
需要注意的是颅悉,js和絕大多數(shù)語言不同沽瞭,他不是以大括號形成的語句塊來區(qū)分作用域的,在我們常見的if,for語句中定義的變量剩瓶,只要是在同一個函數(shù)(同一個作用域)內(nèi)驹溃,則即便for語句和if語句執(zhí)行完成城丧,變量也不會被銷毀,這點(diǎn)非常重要豌鹤。
因此一定要注意布疙,尤其是在for語句中蚊惯,被定義的循環(huán)變量在運(yùn)行結(jié)束后不會被銷毀。而是繼續(xù)存在于它所處的作用域的變量對象中灵临。
聲明變量截型。當(dāng)使用var來聲明變量時,一般情況下會將變量添加到最近的函數(shù)環(huán)境的變量對象中儒溉。在函數(shù)內(nèi)部宦焦,就是函數(shù)環(huán)境。如果在沒有使用var來聲明顿涣,則該變量默認(rèn)為全局變量赶诊。
查詢標(biāo)識符的過程寓调。如昨天我的插圖所示:
3.垃圾收集
js中的垃圾回收機(jī)制是自動垃圾回收锌唾。即系統(tǒng)自動判斷哪些變量已經(jīng)沒有用處,可以銷毀釋放內(nèi)存夺英。時下幾乎全部流行語言都擁有自動垃圾回收的機(jī)制晌涕。這使得開發(fā)人員不必像在使用C/C++時,需要人工地跟蹤變量的內(nèi)存占用情況痛悯,并且在必要的時刻釋放變量所占取的內(nèi)存余黎。
自動垃圾回收的基本原理非常簡單:找出不再被使用的變量 - > 周期性回收這些不會再被使用的變量,釋放對應(yīng)內(nèi)存载萌。
簡單解釋以下一個變量從被聲明到被銷毀的聲明周期:
當(dāng)一個變量在環(huán)境內(nèi)被聲明后惧财,其在棧內(nèi)存中得到相應(yīng)的內(nèi)存分配。函數(shù)執(zhí)行過程中扭仁,變量被使用垮衷。當(dāng)環(huán)境內(nèi)所有的語句執(zhí)行結(jié)束后,變量被打上可以銷毀的標(biāo)記乖坠,當(dāng)垃圾回收的任務(wù)周期性啟動時搀突,他會回收所有被打上可銷毀標(biāo)記的變量。但這是最理想的情況熊泵,實(shí)際操作起來遠(yuǎn)比這復(fù)雜的多仰迁。標(biāo)記無用變量是一個很復(fù)雜的流程甸昏。
在標(biāo)記無用變量這個問題里,核心是兩個:1.標(biāo)記策略徐许,2.標(biāo)記方法施蜜。對于開發(fā)人員來說,必須掌握常見的標(biāo)記策略绊寻,而實(shí)際的標(biāo)記方法知道原理即可花墩。
3.1標(biāo)記清除
標(biāo)記清除是js最常用的標(biāo)記策略。
當(dāng)一個變量進(jìn)入環(huán)境時(例如在函數(shù)中被聲明)澄步,該變量被標(biāo)記上‘進(jìn)入環(huán)境’的標(biāo)記冰蘑。理論上講,任何被標(biāo)記為'進(jìn)入環(huán)境'的變量都不能被清除村缸,因?yàn)榄h(huán)境很可能使用他們祠肥。當(dāng)一個變量離開環(huán)境時(函數(shù)執(zhí)行完畢),該變量被標(biāo)記上‘離開環(huán)境’的標(biāo)記梯皿。
標(biāo)記的方法有很多種仇箱,使用一個列表記錄,或者翻轉(zhuǎn)變量的某個特殊的位來進(jìn)行標(biāo)記东羹,總之標(biāo)記的方法五花八門各種各樣剂桥。但是i正如上文所說,這些都不重要属提,重要的是策略权逗。
3.2引用計(jì)數(shù)
引用計(jì)數(shù)說白了就是計(jì)算有多少個變量指向同一個對象。當(dāng)有大于一個引用類型的變量指向一個對象時冤议,說明該對象有效斟薇,可以被訪問。而當(dāng)沒有任何引用類型的變量指向一個對象時恕酸,說明該對象已經(jīng)無法被訪問堪滨,因此可以銷毀釋放內(nèi)存。
舉例說明:當(dāng)定義一個變量A指向一個對象object時蕊温,這個object的引用計(jì)數(shù) = 1袱箱,如果此時定義一個變量B = A,則這個object的引用計(jì)數(shù) = 1+1义矛,如果此時將A與B分別重新指向object1和object2犯眠,那么object的引用計(jì)數(shù) = 2-1-1 = 0,此時object再也無法被訪問症革,因此可以標(biāo)記筐咧。當(dāng)下次垃圾收集job執(zhí)行時,object對象就會被銷毀。
但是引用計(jì)數(shù)里存在一個嚴(yán)重的BUG量蕊,即引用循環(huán):
假如如圖所示的情況在某個函數(shù)中存在铺罢,而這個函數(shù)又被大量復(fù)用,那么該函數(shù)每運(yùn)行一次残炮,就會有兩個變量無法銷毀韭赘,即由此就會產(chǎn)生嚴(yán)重的內(nèi)存泄露問題。
當(dāng)代雖然絕大多數(shù)瀏覽器都放棄了引用計(jì)數(shù)而完全使用標(biāo)記清除的策略势就,但這種隱患仍然需要重視泉瞻,因?yàn)檫@個問題真實(shí)存在于現(xiàn)實(shí)的工程開發(fā)過程里:在IE9以前的瀏覽器里,其BOM于DOM對象是基于C+COM對象的形式來實(shí)現(xiàn)的苞冯,而COM對象的垃圾回收策略就使用的是引用計(jì)數(shù)袖牙,換句話說,只要IE中涉及到COM對象的地方舅锄,就可能存在內(nèi)存泄漏鞭达。
3.3垃圾回收的性能問題
因?yàn)槔厥帐且粋€周期性運(yùn)行的過程,因此定義其運(yùn)行周期是一個值得思考的問題皇忿。在古老版本的IE(7以前)系統(tǒng)里畴蹭,IE采取的是臨界值啟動的方式,即當(dāng)且僅當(dāng)內(nèi)存中存在 256個變量 || 4096個對象或數(shù)組字面量和數(shù)組元素 || 64KB的字符串時鳍烁,啟動垃圾回收叨襟。可這帶來一個巨大的問題:即如果這些變量大多都定義在全局變量中的話幔荒,則垃圾回收機(jī)制將被被頻繁地啟動芹啥,而這將極大地影響瀏覽器的性能。
IE7以后铺峭,垃圾回收機(jī)制得到了重寫,使得這個臨界值得以動態(tài)修正汽纠。
3.4內(nèi)存管理
盡管js有自動垃圾回收機(jī)制莉炉。但是我們在實(shí)際書寫代碼地過程中最好養(yǎng)成手工釋放變量的好習(xí)慣。這是因?yàn)閷?shí)際上碴犬,系統(tǒng)分配給瀏覽器的內(nèi)存一般遠(yuǎn)少于桌面應(yīng)用程序絮宁,目的是防止瀏覽器吃盡系統(tǒng)內(nèi)存而導(dǎo)致系統(tǒng)崩潰。而瀏覽器得到的有限內(nèi)存則會影響變量分配服协,調(diào)用棧绍昂,以及在一個棧內(nèi)可以運(yùn)行的語句數(shù)量。因此我們推薦在實(shí)際書寫代碼中,對于不再使用的變量窘游,我們應(yīng)該手工釋放其內(nèi)存唠椭。
簡單來說,就是對象數(shù)據(jù)如果不再用了忍饰,就把他的值設(shè)置為null贪嫂。即解除引用。
但是仍然需要說明的一點(diǎn)是赢织,解除引用不代表釋放內(nèi)存亮靴。解除引用的實(shí)質(zhì)是為這個變量打上可以回收的標(biāo)記,方便自動垃圾回收機(jī)制回收他們敌厘。
4.小結(jié)
① js的變量類型分兩類:基本類型和引用類型台猴,基本類型有五種:boolean,string俱两,number饱狂,null,undefined宪彩。
② 基本類型在內(nèi)存中占據(jù)固定大小休讳,保存在棧內(nèi)存中。
③ 從一個變量復(fù)制一個變量尿孔,是創(chuàng)建該值的副本(引用復(fù)制引用俊柔,基本類型復(fù)制基本類型)
④ 引用類型的值實(shí)質(zhì)上一個指針,它指向內(nèi)存中的某個對象活合。
⑤ 復(fù)制引用類型實(shí)際上是復(fù)制一根指向相同對象的指針雏婶。
⑥ 確定基本值類型可以使用typeof(),確定引用類型可以使用instanceof()。
⑦ 所有引用類型都存儲在執(zhí)行環(huán)境(又稱作用域)中白指,它控制著變量的生命周期留晚,以及訪問數(shù)據(jù)的權(quán)限。
⑧ 執(zhí)行環(huán)境分為全局環(huán)境與函數(shù)環(huán)境告嘲。
⑨ 每次進(jìn)入一個新的執(zhí)行環(huán)境則會創(chuàng)建一個新的作用域鏈错维,用于搜索語句中需要的變量和函數(shù)(由內(nèi)向外)
⑨ 變量的執(zhí)行環(huán)境有助于垃圾回收。
⑩ 離開作用域的值會被標(biāo)記上可以回收的標(biāo)記橄唬。
11. 離開作用域的值會被垃圾回收機(jī)制回收
12. 兩種垃圾回收策略:標(biāo)記清除 和 引用計(jì)數(shù)赋焕。
13. 在引用計(jì)數(shù)策略中,循環(huán)引用會導(dǎo)致內(nèi)存泄漏(垃圾回收機(jī)制失效)
14. 隨時手工解除不再使用的對象的引用(把引用類型的變量設(shè)為null)是個好好好好好習(xí)慣仰楚!