匿名函數和閉包


 

一、匿名函數

匿名函數就是沒有名字的函數,又稱作Lambda函數。好多資料說它強大,它到底強大在哪

1 function foo(arg1,arg2,arg3){
2     //code  
3 }
4 
5 var foo = function(arg1,arg2,arg3){
6     //code  
7 }

這兩者區別在哪?

  第一個我們稱作是函數聲明 ,聲明方式無非就是數據類型名,后面接空格和一個變量,就跟C++中的 int a ,char *c一樣

  第二個函數稱作函數表達式,表達式就是類似於 var a = b + c,string = stringA + stringB等

  它們的區別就是函數聲明會在代碼執行以前記載到作用域中,后者是在代碼執行到那一行的時候才會有定義,才會去查找 a ,string到底是什么東東。

  另一個重要的區別是,函數聲明給函數定義了一個名字foo ,而函數表達式是創建了一個匿名函數,這個函數誰都無法調用,但是它將指針賦值給foo以后,foo就可以去調用這個函數。

  為什么要使用匿名函數,單單的函數聲明難道不夠嗎?

1 function foo(arg1,arg2){
2     return function(arg3,arg4){
3     //code
4     }
5 }

函數執行結果返回的函數可以賦值給一個變量,或者以其他方式調用。在把函數當成值使用的情況下都可以使用匿名函數。

note:arguments.callee指向一個正在執行的函數指針,arguments.callee.caller是執行當前函數的一個對象或者說一個環境。

二、作用域鏈

  在講閉包前,先說一下作用域鏈,

  執行環境:execution context

  每個函數在被調用時會創建自己的執行環境,當執行流進入這個函數時,函數的環境變會被推入到一個環境棧中。當函數執行之后,棧將其環境彈出,控制權返回給之前的執行環境(其實這個執行環境就是作用域鏈的具體化)。

  變量對象構成一個作用域鏈,作用域鏈保證了程序的按序正常運行

三、閉包

閉包是什么,閉包就是可以訪問另一個函數作用域中變量的函數。

一般來講,當函數執行完畢之后,,局部的活動對象被銷毀,,內存中只包含全局作用域。

創建方式:

  就是在一個函數中創建另一個函數。

  在匿名函數從函數foo中返回后,它的作用域鏈被初始化為包含foo函數的活動對象和全局變量對象。這樣匿名函數就可以訪問在foo中定義的所有變量。跟重要的是foo函數執行完畢之后,他的活動對象時不會被銷毀的,因為匿名函數的作用域鏈仍然引用這個活動對象。只有當匿名函數銷毀后,foo的活動對象才會被銷毀。

使用范圍:

  1.模仿塊級作用域!

  何為塊級作用域?就是在這個語句塊中有定義,脫離了以后自動銷毀!

  

1 function foo(num){
2     for(var i =0;i<count;i++){
3         //console.log(i);  
4     }  
5      //var i;重新聲明也沒用
6     
7      alert(i); 
8 }    

 

  如上,在C,C++,java又塊級作用域的語言中,if ,for語句中的變量聲明會在語句執行完后銷毀,但是javascript會自動添加到當前的執行環境中。因此i為num,即使重新聲明也會是num。因為它會對后續的聲明視為不見。

  匿名函數可以用來模仿塊級作用域來避免由於各種寫法,本來不想定義的變量存在全局中,無法銷毀的問題

1 (function(){
2     //塊級作用域
3 })();

  這種技術長在全局作用域中被用在函數外部,從而限制向全局作用域中添加過多的變量和函數。一般來說我們應該盡量減少向全局作用域中添加過多的變量和函數。在一個有很多開發人員共同參與的大型應用程序中,過多的全局變量和函數會導致命名沖突,而通過創建私有作用域,每個開發人員可以使用自己的變量, 不用擔心搞壞全局作用域。

  2.靜態私有變量的方法:

 1 (function(){
 2     var name = '';
 3     Person = function(value){
 4         name = value;
 5     }
 6     Person.prototype.getName = function(){
 7         console.log("name",name)
 8         return name;
 9     }
10     Person.prototype.setName = function(value){
11         name = value;
12     }
13 })();
14 //靜態變量只要有一個對象跟改,其他的都跟着更改
15 var p1 = new Person("我是第一");
16 var p2 = new Person('我是第二');
17 p1.getName();   //我是第二
18 p2.getName();   //我是第二
19 
20 p1.setName("我變了");
21 p1.getName();   //我變了
22 p2.getName();   //我變了

  3.模塊模式初探:

前面的模式是用於自定義類型創建私有變量和特權方法。而道格拉斯所說的模塊模式(Module Pattern)則是為單例創建私有變量和特權方法。所謂的單例就是一個實例的對象。

  單例:

1 var singleton = {
2     name:value,
3     method: function(){
4 
5     }           
6 }

模塊通過為單例添加私有變量和方法使其增強。

在Web App中,經常需要使用一個單例來管理應用程序級的信息,比如下面的模塊管理器。

 1 //模塊管理器
 2 var moduleManger = function(){
 3     var _count = 0;
 4     var _module = {};
 5     
 6     var get = function(key){
 7         return _module[key];
 8     }
 9     var set = function(key,value){
10         _module[key] = value;
11         _count ++;
12     }
13     //delete
14     var remove = function(key){
15         delete _module[key];  
16         _count--;
17     }
18     return {
19         get : get,
20         set : set,
21         add : add,
22         remove : remove
23     }
24 }();

 

 

簡言之,如果你必須創建一個對象並以某些數據對其初始化,同時還要公布一些能夠訪問這些私有數據的方法, 就可以使用模塊模式。以這種模式創建的每個實例都是Object實例,最終通過一個字面量來表示它。

 

注:module pattern是javascript的一種高級設計模式,有時間更新。

由於閉包會攜帶包含它的函數作用域,因此會比其他的函數占用更多的內存,不宜過多的使用,但是用的好的話還是非常值得推薦的。

  

 

 

 


免責聲明!

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



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