js閉包

接觸過javascript的人應該聽過閉包(closure),有一種觀點認爲是閉包賦予了javascript的強大能力,也賦予了它具有OOP的特徵。既然javascript closure如此重要,那麼問題來了,什麼是closure呢?closure有什麼做用?本文將結合我本身對closure的理解,用盡可能通俗易懂的方式來進行闡述。javascript

  先看看老外對closure怎麼定義的?A closure is an inner function that has access to the outer (enclosing) function's variables—scope chain.從字面上來看,能夠翻譯爲:閉包就是一個內部函數,它具有訪問外部函數變量(這些變量位於做用域鏈中)的能力[注意變量不包含this和arguments]。但這個概念仍是過於「專業化」, 不接地氣,只從概念上來看,很是抽象。下面用一段JS來對應解釋閉包的概念:java

我的理解爲:fInner函數定義在fOuter的內部,能夠訪問fOuter定義的變量,這個fInner函數就是closure。closure的 scope chain有3個:一個是fInner函數定義的變量;一個是外部fOuter的變量;還有一個是全局變量(global variables)。closure的做用能夠保留變量的值。換句話說,函數fInner就是一個closure。閉包

  closure能夠幹2件事情:函數

  1)closure能夠調用(閉包存儲的外部變量是引用而不是值,這點很是重要)在當前函數之外的定義的變量(即便外部函數已經返回);this

  2)closure能夠修改外部定義的變量值。spa

下面經過一段JS代碼來闡述爲何閉包存儲的外部變量是引用而不是值,這點很是重要!翻譯

 

複製代碼
1     function mixFunction(a)
 2     {
 3         var result=[],i,n;
 4         n=a.length;
 5         for(i=0;i<n;i++){
 6             result[i]=function(){
 7                 //Closure對外部變量是引用
 8                 console.log("for i="+i);
 9                 return a[i];//a[i-1]
10             }
11         }
12         return result;
13     }
14     var mixcall=mixFunction([10,20,30]);
15     var f=mixcall[0];
16     console.log(f());//?應該輸出什麼值
複製代碼

 

f()會輸出 10 麼?答案是undefined!!!code

爲何是這樣的呢? 由於閉包對i是引用,在for循環時,會不斷更新i的值。即在調用f()後,i已經被修改成3 (i===3),而a[3]爲undefined!!blog

上述的代碼始終會輸出a[2]的值,也就是30。ip

 那麼問題來了?怎麼解決該問題呢?這就要用到JS中的IIFE技術啦!IIFE技術來解決JS缺乏塊級做用域的解決方案。以下代碼所示:

複製代碼
1     function mixFunctionFix(a)
 2     {
 3         var result=[],i,n;
 4         n=a.length;
 5         for(i=0;i<n;i++){
 6             //IIFE技術來解決JS缺乏塊級做用域的解決方案
 7             (function(j){
 8                 result[i]=function(){
 9                     //Closure對外部變量是引用
10                     console.log("for j="+j);
11                     return a[j];
12                 }
13             })(i)
14         }
15         return result;
16     }
17     var mixcall=mixFunctionFix([10,20,30]);
18     var f=mixcall[0];
19     console.log(f());//10
複製代碼

 前面提到JS閉包能夠實現OOP的特徵,下面給出JS如何定義一個「User類」(實際是一個JS函數)。此函數有私用變量和方法,同時也具備公開的方法。私有變量和方法不能函數外部調用:

複製代碼
1     function User(){
 2         //private properties
 3         var _name = '';
 4         var _age  = 0;
 5      
 6         //private method
 7         function privateMethod(){
 8             return "private  Method"
 9         };
10         //public method
11         this.setName = function(name){
12             //can call
13             privateMethod();
14             _name = name;
15             return this;
16         };
17      
18         this.setAge = function(age){
19             _age = age;
20             return this;
21         };
22         this.getAge = function(){
23             return _age;
24         };
25         this.getName = function(){
26             return _name;
27         };
28     }
29     var p=new User();
30     console.log(p.setName('jackwang').setAge(28));
31     console.log(p.getName());//jackwang
32     console.log(p.getAge());//28
33     console.log(p._name);//undefined 
34     console.log(p.privateMethod());//error
複製代碼

私有變量_name和_age以及私有方法privateMethod()都不能在函數外部調用。User設置name和age只能經過公開方法setName和setAge進行,獲取只能經過getName和getAge進行訪問。

有人會問,這個是閉包麼?看下圖:

相關文章
相關標籤/搜索