<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    魚躍于淵

    First know how, Second know why !
    posts - 0, comments - 1, trackbacks - 0, articles - 49

    javascript的作用域和閉包

    Posted on 2008-12-23 11:20 魚躍于淵 閱讀(287) 評論(0)  編輯  收藏 所屬分類: javascript相關

    作者:瀟湘客老師

    閉包是通過在對一個函數調用的執行環境中返回一個函數對象構成的。比如,在對函數調用的過程中,將一個對內部函數對象的引用指定給另一個對象的屬性。或者,直接將這樣一個(內部)函數對象的引用指定給一個全局變量、或者一個全局性對象的屬性,或者一個作為參數以引用方式傳遞給外部函數的對象。例如:-

    function exampleClosureForm(arg1, arg2){
    var localVar = 8;
    function exampleReturned(innerArg){
    return ((arg1 + arg2)/(innerArg + localVar));
    }
    /* 返回一個定義為 exampleReturned 的內部函數的引用 -:- */ return exampleReturned;
    }

    var globalVar = exampleClosureForm(2, 4);
    這種情況下,在調用外部函數 exampleClosureForm 的執行環境中所創建的函數對象就不會被當作垃圾收集,因為該函數對象被一個全局變量所引用,而且仍然是可以訪問的,甚至可以通過 globalVar(n) 來執行。

    的確,情況比正常的時候要復雜一些。因為現在這個被變量 globalVar 引用的內部函數對象的 [[scope]] 屬性所引用的作用域鏈中,包含著屬于創建該內部函數對象的執行環境的活動對象(和全局對象)。由于在執行被 globalVar 引用的函數對象時,每次都要把該函數對象的 [[scope]] 屬性所引用的整個作用域鏈添加到創建的(內部函數的)執行環境的作用域中(即此時的作用域中包括:內部執行環境的活動對象、外部執行環境的活動對象、全局對象。譯者注), 所以這個(外部執行環境的)活動對象不會被當作垃圾收集。

    閉包因此而構成。此時,內部函數對象擁有自由的變量,而位于該函數作用域鏈中的活動(可變)對象則成為與變量綁定的環境。

    由于活動(可變)對象受限于內部函數對象(現在被 globalVar 變量引用)的 [[scope]] 屬性中作用域鏈的引用,所以活動對象連同它的變量聲明--即屬性的值,都會被保留。而在對內部函數調用的執行環境中進行作用域解析時,將會把與活動(可變)對象的命名屬性一致的標識符作為該對象的屬性來解析。活動對象的這些屬性值即使是在創建它的執行環境退出后,仍然可以被讀取和設置。

    在上面的例子中,當外部函數返回(退出它的執行環境)時,其活動(可變)對象的變量聲明中記錄了形式參數、內部函數定義以及局部變量的值。arg1 屬性的值為 2,而 arg2 屬性的值為 4,localVar 的值是 8,還有一個 exampleReturned 屬性,它引用由外部函數返回的內部函數對象。(為方便起見,我們將在后面的討論中,稱這個活動<可變>對象為 "ActOuter1")。

    如果再次調用 exampleClosureForm 函數,如:-

    var secondGlobalVar = exampleClosureForm(12, 3);
    - 則會創建一個新的執行環境和一個新的活動對象。而且,會返回一個新的函數對象,該函數對象的 [[scope]] 屬性引用的作用域鏈與前一次不同,因為這一次的作用域鏈中包含著第二個執行環境的活動對象,而這個活動對象的屬性 arg1 值為 12 而屬性 arg2 值為 3。(為方便起見,我們將在后面的討論中,稱這個活動<可變>對象為 "ActOuter2")。

    通過第二次執行 exampleClosureForm 函數,第二個、也是截然不同的閉包誕生了。

    通過執行 exampleClosureForm 創建的兩個函數對象分別被指定給了全局變量 globalVar 和 secondGlobalVar,并返回了表達式 ((arg1 + arg2)/(innerArg + localVar))。該表達式對其中的四個標識符應用了不同的操作符。如何確定這些標識符的值是體現閉包價值的關鍵所在。

    我們來看一看,在執行由 globalVar 引用的函數對象--如 globalVar(2)--時的情形。此時,會創建一個新的執行環境和相應的活動對象(我們將稱之為“ActInner1”),并把該活動對象添加到執行的函數對象的 [[scope]] 屬性所引用的作用域鏈的前端。ActInner1 會帶有一個屬性 innerArg,根據傳遞的形式參數,其值被指定為 2。這個新執行環境的作用域鏈變成: ActInner1->ActOuter1->全局對象.

    為了返回表達式 ((arg1 + arg2)/(innerArg + localVar)) 的值,要沿著作用域鏈進行標識符解析。表達式中標識符的值將通過依次查找作用域鏈中每個對象(與標識符名稱一致)的屬性來確定。

    作用域鏈中的第一個對象是 ActInner1,它有一個名為 innerArg 的屬性,值是 2。所有其他三個標識符在 ActOuter1 中都有對應的屬性:arg1 是 2,arg2 是 4 而 localVar 是 8。最后,函數調用返回 ((2 + 2)/(2 + 8))。

    現在再來看一看由 secondGlobalVar 引用的同一個函數對象的執行情況,比如 secondGlobalVar(5)。我們把這次創建的新執行環境的活動對象稱為 “ActInner2”,相應的作用域鏈就變成了:ActInner2->ActOuter2->全局對象。ActInner2 返回 innerArg 的值 5,而 ActOuter2 分別返回 arg1、arg2 和 localVar 的值 12、3 和 8。函數調用返回的值就是 ((12 + 3)/(5 + 8))。

    如果再執行一次 secondGlobalVar,則又會有一個新活動對象被添加到作用域鏈的前端,但 ActOuter2 仍然是鏈中的第二個對象,而他的命名屬性會再次用于完成標識符 arg1、arg2 和 localVar 的解析。

    這就是 ECMAScript 的內部函數獲取、維持和訪問創建他們的執行環境的形式參數、聲明的內部函數以及局部變量的過程。這個過程說明了構成閉包以后,內部的函數對象在其存續過程中,如何維持對這些值的引用、如何對這些值進行讀取的機制。即,創建內部函數對象的執行環境的活動(可變)對象,會保留在該函數對象的 [[scope]] 屬性所引用的作用域鏈中。直到所有對這個內部函數的引用被釋放,這個函數對象才會成為垃圾收集的目標(連同它的作用域鏈中任何不再需要的對象)。

    內部函數自身也可能有內部函數。在通過函數執行返回內部函數構成閉包以后,相應的閉包自身也可能會返回內部函數從而構成它們自己的閉包。每次作用域鏈嵌套,都會增加由創建內部函數對象的執行環境引發的新活動對象。ECMAScript 規范要求作用域鏈是臨時性的,但對作用域鏈的長度卻沒有加以限制。在具體實現中,可能會存在實際的限制,但還沒有發現有具體限制數量的報告。目前來看,嵌套的內部函數所擁有的潛能,仍然超出了使用它們的人的想像能力。
     
    UID50579 帖子297 精華0 下載幣114 枚 金幣236 枚 閱讀權限200 在線時間131 小時 注冊時間2008-10-2 最后登錄2008-12-22 查看個人網站

    查看詳細資料
     引用 使用道具 報告 回復 TOP
     

    主站蜘蛛池模板: 亚洲男人的天堂在线va拉文| 日韩a在线观看免费观看| 国产性爱在线观看亚洲黄色一级片| 亚洲精品天堂成人片AV在线播放| 久久精品a一国产成人免费网站| 亚洲国产成人超福利久久精品| 亚洲国产精品免费在线观看| 777亚洲精品乱码久久久久久 | 日美韩电影免费看| 亚洲av成人无码网站…| 国产在线观看免费视频播放器 | 国产免费一区二区视频| 亚洲av无码无在线观看红杏| 久久精品电影免费动漫| 亚洲码一区二区三区| 欧美大尺寸SUV免费| 在线观看亚洲免费| 亚洲色中文字幕无码AV| 亚洲国产精品免费视频| 亚洲激情校园春色| 国产精品高清全国免费观看| 一级白嫩美女毛片免费| 亚洲av日韩av无码黑人| 九九精品免费视频| 日韩少妇内射免费播放| 无码乱人伦一区二区亚洲| 无码日韩人妻av一区免费| 黄色毛片免费网站| 亚洲A∨无码无在线观看| 成年午夜视频免费观看视频| 成年网站免费入口在线观看 | 成年人视频在线观看免费| 看Aⅴ免费毛片手机播放| 亚洲VA成无码人在线观看天堂 | 99久热只有精品视频免费观看17| 亚洲国产日韩在线人成下载 | 免费观看激色视频网站bd| 亚洲αⅴ无码乱码在线观看性色| 亚洲精品美女久久777777| 免费无码AV电影在线观看| 国产在线播放线91免费 |