徹底搞清js中閉包(Closure)的概念


js中閉包這個概念對於初學js的同學來說, 會比較陌生, 有些難以理解, 理解起來非常模糊. 今天就和大家一起來探討一下這個玩意.
相信大家在看完后, 心中的迷惑會迎然而解.

閉包概念:


  閉包就是有權訪問另一個函數作用域中變量的函數.

 

 

分析這句話:

  1.閉包是定義在函數中的函數.
  2.閉包能訪問包含函數的變量.
  3.即使包含函數執行完了, 被閉包引用的變量也得不到釋放.

 

例子分析-1:
    
        function add(){
            var i = 0
                arr = [];
            for(; i < 10; i++){
                arr.push(function(){
                    alert(i);
                });
            }
            return arr;
        }
        var temp = add();
        temp[0]();
        
        大家猜猜這個結果是多少? 0, i, 10?
        我想大家會說是0.
        但是結果是10.
        
        我想大家想的應該是這樣滴:
         i = 0, arr.push(function(){
            alert(0);
         })
         i = 1, arr.push(function(){
            alert(1);
         })
        ...
         i = 10, arr.push(function(){
            alert(10);
         })
         
        咋一看, 這個確實合理, 根據閉包的定義, 具體這個當然是上面分析的那樣了.
        問題就出在這個變量的理解上.
        
        1.i是變量不假, 但是i在for循環的時候, 一直在不斷變化. 也就是說這個i在參與for循環的時候, 值是不確定的, 等到for執行完后, i的值才確定.
        2.每次push一個匿名函數表達式時, 那只是定義一個函數, 並沒去執行那個函數, 所以那個函數里引用的外部變量都是原封不動的放進去的. 換句話說, 就是這個匿名函數在最后執行的時候, 才會去查找作用域鏈, 直至找到那個變量i為止.
        
        也就是:
             i = 0, arr.push(function(){
                alert(i);
             })
             i = 1, arr.push(function(){
                alert(i);
             })
             ...
             i = 10, arr.push(function(){
                alert(i);
             })
        
        執行add()時, i參與循環完畢, i = 10. 
        執行temp[0]()時, 匿名函數會查找i, 先看自己, 我的i有值嗎?沒有. 再找他的上級函數, i有值嗎?有, i = 10. 查找結束.
        至此, 不管執行temp[0](), 還是temp[5](), 還是temp[10](), 結果都是10.
        
        改一下上面的例子, 讓它符合我們的預期要求.
        
        例子分析-2:
        
          function add(){
            var i = 0
                arr = [];
            for(; i < 10; i++){
                arr.push(
                (function(n){
                    return function(){
                        alert(n);
                    }
                })(i)//注意這個變化
);
} return arr; } var temp = add(); temp[0](); temp[1](); ... 這次結果是預期的,結果是 0 , 1 , 2, 3 ... 10 分析一下循環那部分. (function(n){ return function(){ alert(n); } })(i)
這個叫做立即執行的匿名函數表達式(不清楚這種寫法的, 可以先google下, 或者看我的單獨一篇專門介紹) i這個是時候就被當做參數傳遞了, 每次這個匿名函數執行時, i都會把自己的值復制一份給n return語句中的匿名函數引用着n, 此時已經和i無關了. 每次匿名函數表達式執行時, 都會保存一個不同的n. return語句中的匿名函數每次也引用着不同的n。 形象點就是這樣: arr.push( (
function(n = i = 0){ return function(){ alert(n = 0); } })(i = 0) ) arr.push( (function(n = i = 1){ return function(){ alert(n = 1); } })(i = 1) )
...


閉包的介紹就到此為止了.

 


免責聲明!

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



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