js學習筆記之作用域鏈和閉包


 在學習閉包之前我們很有必要先了解什么是作用域鏈

一、作用域鏈

作用域鏈是保證對執行環境有權訪問的所有變量和函數的有序訪問。

這句話其實還是蠻抽象的,但是通過下面一個例子,我們就能清楚的了解到作用域鏈了。

 1 var color="blue";
 2     function changeColor(){
 3         var anotherColor="red";
 4         function swapColors(){
 5             var tempColor=anotherColor;
 6             anotherColor=color;
 7             color=tempColor;
 8             //這里面可以訪問color、anotherColor和tempColor
 9         }
10         //這里面可以訪問anotherColor和color
11     }
12     //這里面只能訪問color

以上代碼涉及了3個執行環境:全局環境、changeColor()局部環境和swapColor()局部環境。在一個變量環境中只能訪問他自己的環境和父執行環境。swapColor()的父執行環境就是changeColor(),而changeColor()的父執行環境就是全局環境。如果還不清楚可以參考下圖

      

在f2()函數的局部環境中能訪問自己和比它等級高的,也就是a,b,c,同理f1()函數環境訪問b,a,全局環境只能訪問c。

我們這時候會發現函數外部是無法訪問內部的局部環境的,但是我們想突破作用域鏈怎么辦呢?這時候就有了閉包共享作用域。閉包這個名詞就出現了。

二、閉包

閉包在紅寶書中的解釋就是:有權訪問另一個函數作用域中的變量的函數。

下來舉一個簡單的例子

1  function f1(){
2         var a=1;
3         return function(){
4             return a;
5         }
6     }
7     alert(a);  /*結果為 a is undefined*/
8     var task=f1(); /*task就是閉包,有權訪問其他函數作用域變量*/
9     alert(task());/*結果為1*/

下來我們再舉一個閉包的例子

 1 function f1(){  
 2       var n=0;
 3       task=function(){  //匿名函數
 4           n+=1;
 5       }
 6       //這部分為閉包
 7       function f2(){    
 8           alert(n);
 9       }
10       return f2 //返回       
12   }
13     var text=f1(); 
14     alert(text()); 
15     task();
16     alert(text()); //結果依次為 0,undefined,1,undefined

text是f2閉包函數,實際上f2()被賦予一個全局變量,f2()始終在內存中,f1()是它的父級函數,所以f1()也始終在內存中,不會被銷毀。執行一次task()后,值變為2。至於為什么會出現undefined是因為,undefined是text的返回值,也就是閉包函數無返回值了。

有時候我們想改變其他函數作用域里的變量,這時候就可以用閉包去解決。設置兩個額外的函數去訪問內部函數。

 1 var setvalue,getvalue;
 2 (function(){
 3     var n=0;
 4     getvalue=function(){
 5         return n
 6     }
 7     setvalue=function(x){
 8         n=x;
 9     }
10 })(); //直接調用
11 alert(getvalue()); //結果為0
12 setvalue(456);
13 alert(getvalue());/*結果為456*/

這時候我們發現在外部就可以去改變內部變量值。

下來再舉一個利用閉包循環遍歷得到數組的值。有兩個程序,可以對比一下兩個程序的區別

例1:

 1 function f1(){
 2     var a=[];
 3     var i=0;
 4     for(i=0;i<3;i++){
 5         a[i]=function(){
 6             return i;
 7         }
 8     }
 9     return a;
10 }
11   var text=f1();
12     alert(text[0]()); 
13     alert(text[1]());
14     alert(text[2]()); //結果都為3

因為閉包都指向局部變量i,只是給出了指針鏈接,對變量的引用,並沒有對值作出改變。所以結果都為3

例2:

 1  function f1(){
 2        function f2(x){  //閉包
 3            return function(){
 4                return x;
 5            }
 6        }
 7        var a=[];
 8        var i=0;
 9        for(i=0;i<3;i++){
10            a[i]=f2(i);
11        }
12        return a;
13    }
14     var text=f1();
15     alert(text[0]()); //結果為1
16     alert(text[1]());//結果為2
17     alert(text[2]());//結果為3

利用一個函數參數,用閉包去獲取內部變量的值。

程序是這樣走的:先判斷誰進來--》調用閉包--》閉包返回內部函數參數--》最后再創建數組。

三、閉包的缺點

  這上面幾個例子確實體會到了閉包的強大,但是閉包也有明顯的缺點,它使函數中的變量都保存在內存中,占用內存,導致頁面加載緩慢。所以再退出函數前,將不用的局部變量刪除。

四、總結

  以上就是我學習閉包總結的一點小知識。大家互相交流哈 O(∩_∩)O。

  附阮一峰老師對閉包的理解:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html?20120612141317#comments 

  

 

 

 

 

 

 


免責聲明!

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



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