JavaScript閉包——實現

閉包的官方的解釋是:一個擁有許多變量和綁定了這些變量的環境的表達式(一般是一個函數),於是這些變量也是該表達式的一部分。javascript

通俗點的說法是:html

  1. 從理論角度:全部的函數。由於它們都在建立的時候就將上層上下文的數據保存起來了。哪怕是簡單的全局變量也是如此,由於函數中訪問全局變量就至關因而在訪問自由變量,這個時候使用最外層的做用域。java

  2. 從實踐角度:如下函數纔算是閉包:git

            即便建立它的上下文已經銷燬,它仍然存在(好比,內部函數從父函數中返回)
            在代碼中引用了自由變量(自由變量:是指在函數中使用的,但既不是函數參數也不是函數的局部變量的變量)
複製代碼
        function testFreedom() {
            var freedomVar = 1;
            function inner(param) {
                echo(pclosure1, param + freedomVar);//將結果打印到pclosure1中
            }
          return inner;
        }
複製代碼

對於inner函數來講,freedomVar就屬於自由變量。github

 

1、一個實現

<p id="closure1" style="color:red"></p>
複製代碼
     function echo(p, html) {
            p.innerHTML += html + '<br/>';
        }
     function closure() {
            var innerVar = 0;
            function inner() {
                return ++innerVar;
            }
            return inner;
        }
        var quote = closure();
        echo(pclosure1, quote());//1
        echo(pclosure1, quote());//2
複製代碼

先看看結果狀況:web

一、第一次quote函數的結果爲1,第二次爲2shell

二、inner嵌套在函數closure內部;函數closure返回函數inner編程

三、結合上面的閉包實踐角度特色,能夠得出closure是一個閉包瀏覽器

四、函數closure在返回後不會被GC回收,緣由以下:閉包

  1. closure返回函數inner的引用給quote

  2. 函數inner的做用域鏈包含了對函數closure的活動對象(activation_1)的引用,以下圖所示。

  3. inner能夠訪問到closure中定義的全部變量和函數

  4. 函數inner被quote引用

  5. 函數inner又依賴函數closure

 

2、大體的做用域圖

 

3、closure裏面的大體執行步驟

1) 初始化Global Object即window對象,Variable Object(全局執行環境中的可變對象)爲window對象自己。建立Scope Chain對象,假設爲scope_1,其中只包含window對象

2) 掃描JavaScript源代碼,從結果中能夠獲得定義的變量名、函數對象。按照掃描順序:

  1. 發現函數closure的定義,使用這個定義建立函數對象,傳給建立過程的Scope Chain爲scope_1。將結果添加到window的屬性中,名字爲closure,值爲返回的函數對象

  2. 發現變量quote,在window對象上添加quote屬性,值爲undefined

3) 執行函數closure,獲得返回值:

  3.1 建立Activation Object,假設爲activation_1;建立一個新的Scope Chain,假設爲scope_2,scope_2中第一個對象爲activation_1,第二個對象爲window對象

  3.2 處理參數列表。建立arguments對象並進行設置,將arguments設置爲activation_1的屬性

  3.3 對closure的函數體執行相似步驟2的處理過程:

  1. 發現變量innerVar,在activation_1對象上添加innerVar屬性,值爲undefined

  2. 發現函數inner的定義,使用這個定義建立函數對象,傳給建立過程的Scope Chain爲scope_2(函數closure的Scope Chain)。將結果添加到activation_1的屬性中,名字爲inner,值爲返回的函數對象。inner的內部 [[Scope]]就是scope_2

  3.4 執行innerVar賦值語句,賦值爲"0"

  3.5 執行inner:

  1. 建立Activation Object,假設爲activation_2;建立一個新的Scope Chain,假設爲scope_3,scope_3中第一個對象爲activation_2,接下來的對象依次爲activation_一、window 對象(取自fn2的[[Scope]],即scope_2)

  2. 處理參數列表。由於inner沒有參數,因此只用建立arguments對象並設置爲activation_2的屬性

  3. 對inner的函數體執行相似步驟2的處理過程,沒有發現變量定義和函數聲明

  4. 執行函數體。對任何一個變量引用,從scope_3上進行搜索,這個示例中,innerVar將在activation_1上找到

  5. 返回inner的返回值

  3.6 返回結果

4) 打印結果

 

 

 

demo下載:

http://download.csdn.net/download/loneleaf1/8019865

 

參考資料:

http://www.nowamagic.net/librarys/veda/detail/1707 JavaScript閉包其一:閉包概論

http://www.nowamagic.net/librarys/veda/detail/1708 JavaScript閉包其二:閉包的實現

http://www.nowamagic.net/librarys/veda/detail/1709 JavaScript閉包其三:閉包的用法

http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html 簡單易懂的JavaScript閉解

http://page.renren.com/601017893/note/801095804 Javascript 閉包

http://kb.cnblogs.com/page/110782/ Javascript閉包——懂不懂由你,反正我是懂了

http://coolshell.cn/articles/6731.html 理解Javascript的閉包

http://kb.cnblogs.com/page/105708/ 深刻理解Javascript閉包(closure)

http://www.zhihu.com/question/20032419 動態做用域和詞法域的區別是什麼?

http://kangax.github.io/compat-table/es5/  ECMAScript5瀏覽器兼容表

http://www.nowamagic.net/librarys/veda/detail/1579 咱們應該如何去了解JavaScript引擎的工做原理

http://www.ibm.com/developerworks/cn/web/1006_qiujt_jsfunctional/ JavaScript 中的函數式編程實踐

http://www.cnblogs.com/fool/archive/2010/10/19/1855266.html 理解Javascript_13_執行模型詳解

 

出處:http://www.cnblogs.com/strick/p/3997898.html

相關文章
相關標籤/搜索