原生JS的閉包詳解~~


了解閉包之前我們需要懂的東西:需要知道JS的作用域鏈以及預解析。

      進入話題,作用域鏈上面的東西是存在哪里的呢。 是一個棧結構,最底層是window對象。

棧就是類似一個桶裝結構,如圖1:                               

                                            圖一 :    棧結構具有的特點就是先入后出。 好比你放進桶里的東西,你需要從最上面開始拿出來。

JS代碼的解析過程中:例如JS代碼里有一個函數foo.

                                                              <script>

                   var a = 1;

                                                                  function foo()

                                                                  { }

                    foo();

                                                             </script>

預解析:那么預解析到這個函數時,發生了如下的事情:   由於函數是引用類型的對象,實際數據存在堆里,那么在棧里只存放了地址。0x1101這個地址指向堆的實際數據。

運行到這個函數時,它會創建一個foo的作用域鏈對象。然后存入一個棧里,這個棧底層永遠是window.

 

函數執行=>foo() 又會發生的事情:棧里面的foo創建了一個活動對象。即執行了這個函數。

                                             

 

當函數執行完畢:foo的作用域鏈出棧,沒有被指向的活動對象即銷毀。但是window不會被銷毀。

 

                                             (PS:橡皮擦太小了,沒擦干凈)

 

 

 

 

閉包是什么呢? 官方解答是有權去訪問函數內的變量。

我們現在來寫一個函數:

 
    function foo(){
        var n = 0;
   //返回了一個函數。 這個函數的n 是從foo里面找的n。
return function getNum() { n++; console.log(n);
       return n; } }
var fn = foo();
  fn();

預解析就會多了一步:在執行foo的時候,也就是創建活動對象之后,會再執行 getNum的入棧步驟。getNum被調用時也會創建一個活動對象。但是最后並不會銷毀。

因為fn指向了這個閉環回路。

簡單的講:這個函數被保存在了內存之中,並且一直可以通過fn訪問到。

 

 

 

 

函數調用結束后:如果用fn指向這個getNum的作用域鏈對象。只要fn到getNum的指向沒有消失。那么就可以一直訪問到存儲在內存的n.

閉包的核心就是getNum的活動對象沒有被銷毀,即使fn指向不是這個getNum 這個東西封閉的環也不會注銷,會一直在內存中,這也是閉包的缺點,容易造成內存泄漏。

我們現在來梳理一下閉包的步驟:

1.函數內部嵌套子函數,

2.子函數得到父函數的值。

3.把內層函數返回出去。(但閉包的創建不止這個形式。還有其他的。)

 

 

 

 

 

 

 

 

 

 

 

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM