一.匿名函數數組
匿名函數就是沒有名字的函數。閉包
//普通函數 function laber() { //函數名是laber return 'momo'; } //匿名函數 function () { //匿名函數,會報錯 return 'momo'; } //經過表達式自我執行 (function laber() { //封裝成表達式 alert('momo'); })(); //()表示執行函數,而且傳參 //把匿名函數賦值給變量 var laber = function () { //將匿名函數賦給變量 return 'momo'; }; alert(laber()); //調用方式和函數調用類似 //函數裏的匿名函數 function laber() { return function () { //函數裏的匿名函數,產生閉包 return 'momo'; } } alert(laber()()); //調用匿名函數
二.閉包函數
閉包是指有權訪問另外一個函數做用域中的變量的函數,建立閉包的常見的方式,就是在一個函數內部建立另外一個函數,經過另外一個函數訪問這個函數的局部變量。性能
//經過閉包能夠返回局部變量 function laber() { var name= 'momo'; return function () { //經過匿名函數返回laber()局部變量 return name; }; } alert(laber()()); //經過laber()()來直接調用匿名函數返回值 var b = laber(); alert(b()); //另外一種調用匿名函數返回值
使用閉包有一個優勢,也是它的缺點:就是能夠把局部變量駐留在內存中,能夠避免使用全局變量。(全局變量污染致使應用程序不可預測性,每一個模塊均可調用必將引來災難,因此推薦使用私有的,封裝的局部變量)。this
//經過全局變量來累加spa
var age = 100; //全局變量 function laber() { age ++; //模塊級能夠調用全局變量,進行累加 } laber(); //執行函數,累加了 alert(age); //輸出全局變量
//經過局部變量沒法實現累加code
function laber() { var age = 100; age ++; //累加 return age; } alert(laber)); //101 alert(laber()); //101,沒法實現,由於又被初始化了
//經過閉包能夠實現局部變量的累加對象
function laber() { var age = 100; return function () { age ++; return age; } } var b = laber(); //得到函數 alert(b()); //調用匿名函數 alert(b()); //第二次調用匿名函數,實現累加
因爲閉包裏做用域返回的局部變量資源不會被馬上銷燬回收,因此可能會佔用更多的內存。過分使用閉包會致使性能降低,建議在很是有必要的時候才使用閉包。blog
做用域鏈的機制致使一個問題,在循環中裏的匿名函數取得的任何變量都是最後一個值。內存
//循環裏包含匿名函數
function laber() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = function () { return i; }; } return arr; } var b = laber(); //獲得函數數組 alert(b.length); //獲得函數集合長度 for (var i = 0; i < b.length; i++) { alert(b[i]()); //輸出每一個函數的值,都是最後一個值 }
上面的例子輸出的結果都是5,也就是循環後獲得的最大的i值。由於b[i]調用的是匿名函數,匿名函數並無自我執行,等到調用的時候,laber()已執行完畢,i早已變成5,因此最終的結果就是5個5。
//循環裏包含匿名函數-改1,自我執行匿名函數
function laber() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { //自我執行 return num; })(i); //而且傳參 } return arr; } var b = laber(); for (var i = 0; i < b.length; i++) { alert(b[i]); //這裏返回的是數組,直接打印便可 }
改1中,咱們讓匿名函數進行自我執行,致使最終返回給a[i]的是數組而不是函數了。最終致使b[0]-b[4]中保留了0,1,2,3,4的值。
//循環裏包含匿名函數-改2,匿名函數下再作個匿名函數
function laber() { var arr = []; for (var i = 0; i < 5; i++) { arr[i] = (function (num) { return function () { //直接返回值,改2變成返回函數 return num; //原理和改1同樣 } })(i); } return arr; } var b = laber(); for (var i = 0; i < b.length; i++) { alert(b[i]()); //這裏經過b[i]()函數調用便可 }
改1和改2中,咱們經過匿名函數自我執行,當即把結果賦值給a[i]。每個i,是調用方經過按值傳遞的,因此最終返回的都是指定的遞增的i。而不是laber()函數裏的i。
關於this對象
在閉包中使用this對象也可能會致使一些問題,this對象是在運行時基於函數的執行環境綁定的,若是this在全局範圍就是window,若是在對象內部就指向這個對象。而閉包卻在運行時指向window的,由於閉包並不屬於這個對象的屬性或方法。