一、匿名函數
匿名函數就是沒有名字的函數,又稱作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的一種高級設計模式,有時間更新。
由於閉包會攜帶包含它的函數作用域,因此會比其他的函數占用更多的內存,不宜過多的使用,但是用的好的話還是非常值得推薦的。