《javaScript高級程序設(shè)計》讀書筆記(五)

以下內(nèi)容可能存在個人理解的部分,并非完全參照原文

如有疑問,請以書中內(nèi)容為準

接著上一篇的內(nèi)容

4.2 執(zhí)行環(huán)境及作用域

執(zhí)行環(huán)境定義了變量或函數(shù)有權(quán)訪問的其他數(shù)據(jù),決定了它們各自的行為。每一個執(zhí)行環(huán)境都有一個與之關(guān)聯(lián)的 變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中。

每個函數(shù)都有自己的 執(zhí)行環(huán)境。當執(zhí)行流進入一個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中。而在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。

當代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個 作用域鏈。作用域鏈的前端,始終都是當前執(zhí)行的代碼所在環(huán)境的變量對象。如果這個環(huán)境時函數(shù),則將其 活動對象 作為變量對象。作用域鏈中的下一個變量對象來自包含(外部)環(huán)境,而再下一個變量對象則來自下一個包含環(huán)境,一直延續(xù)到全局執(zhí)行環(huán)境。

簡單來說,內(nèi)部作用域里找不到就到外部作用域去找.

延長作用域鏈

有些語句可以在作用域鏈的前端臨時增加一個變量對象,該變量對象會在代碼執(zhí)行后被移除。

在兩種情況下會發(fā)生這種現(xiàn)象:

  • try-catch語句的catch
  • with語句

with語句來說,會將指定的對象添加到作用域鏈中。對catch語句來說,會創(chuàng)建一個新的變量對象,其中包含的是被拋出的錯誤對象的聲明。

function buildUrl(){
    var qs = "?debug=true";

    with(location){
        var url = href + qs;
    }

    return url;
}

with接收的是location對象,因此其變量對象中就包含了location對象的所有屬性和方法,而這個變量對象被添加到了作用域的前端。

MDN上的with : 不推薦使用with,在 ECMAScript 5 嚴格模式中該標簽已被禁止。推薦的替代方案是聲明一個臨時變量來承載你所需要的屬性。

沒有塊級作用域

在其他類C的語言中,由花括號封閉的代碼塊都有自己的作用域,但JavaScript并沒有塊級作用域

if(true){
    var color = "blue";
}
alert(color);   // "blue"

for循環(huán)中更容易引起迷惑

for(var i=0;i<10;i++){
    doSomething(i);
}
alert(i);   // 10

這個在前面也有提到過

4.3 垃圾收集

JavaScript具有自動垃圾收集機制

標記清除

JavaScript中最常用的垃圾收集方式是 標記清除

當變量進入環(huán)境時,就將這個變量標記為“進入環(huán)境”。而當變量離開環(huán)境時,則將其標記為“離開環(huán)境”。

垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記。然后,它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量。

引用計數(shù)

另一種不太常見的垃圾收集策略叫做 引用計數(shù)

當聲明了一個變量并將一個引用類型賦給該變量時,這個值的引用次數(shù)就是1。如果同一個值又被賦給另一個變量,則該值的引用次數(shù)加1。

相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數(shù)減1。當這個值的引用次數(shù)為0時,則說明沒有辦法再訪問,可以將其占用的內(nèi)存空間回收。

但會存在一個問題: 循環(huán)引用

function problem(){
    var objA = new Object();
    var objB = new Object();

    objA.someOtherObj = objB;
    objB.anotherObj = objA;
}

當函數(shù)執(zhí)行完畢,objA和objB還將繼續(xù)存在,因為它們的引用次數(shù)永遠不會是0

管理內(nèi)存

分配給Web瀏覽器的可用內(nèi)存通常比分配給桌面應(yīng)用的少

優(yōu)化內(nèi)存最佳的方式,就是為執(zhí)行中的代碼只保存必要的數(shù)據(jù)。一旦數(shù)據(jù)不再有用,最好通過將其值設(shè)置為null來釋放其引用——這個做法叫做 解除引用

function createPerson(name) {
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
    // localPerson在函數(shù)執(zhí)行完畢后就離開了其執(zhí)行環(huán)境
    // 不需要顯示地解除引用
}
var globalPerson = createPerson("Nicholas");

//  解除引用
globalPerson = null;

解除引用不意味著自動回收該值占用的內(nèi)存,它的真正作用是讓值脫離執(zhí)行環(huán)境,以便垃圾收集器下次運行時將其回收。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容