轉載自:
http://www.cnblogs.com/ZinCode/p/5551907.html
參考資料:
http://www.tuicool.com/articles/ZR3m2m2
http://www.javashuo.com/article/p-wlxtfjor-cz.html
咱們先看一個正常的for循環,普通函數裏面有一個for循環,for循環結束後最終返回結果數組html
function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = i; } return arr; } alert(box()) //正常狀況不須要閉包,就能夠達到預期效果,輸出結果爲一個數組0,1,2,3,4
有時咱們須要在for循環裏面添加一個匿名函數來實現更多功能,看下面代碼segmentfault
複製代碼 //循環裏面包含閉包函數 function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = function(){ return i; //因爲這個閉包的關係,他是循環完畢以後才返回,最終結果是4++是5 } //這個匿名函數裏面根本沒有i這個變量,因此匿名函數會從父級函數中去找i, } //當找到這個i的時候,for循環已經循環完畢了,因此最終會返回5 return arr; } //alert(box()); //執行5次匿名函數自己 //alert(box()[1]); //執行第2個匿名函數自己 //alert(box().length); //最終返回的是一個數組,數組的長度爲5 alert(box()[0]()); //數組中的第一個數返回的是5,這是爲何?
上面這段代碼就造成了一個閉包:數組
閉包是指有權訪問另外一個函數做用域中的變量的函數,建立閉包的常見的方式,就是在一個函數內部建立另外一個函數,經過另外一個函數訪問這個函數的局部變量。閉包
在for循環裏面的匿名函數執行 return i 語句的時候,因爲匿名函數裏面沒有i這個變量,因此這個i他要從父級函數中尋找i,而父級函數中的i在for循環中,當找到這個i的時候,是for循環完畢的i,也就是5,因此這個box獲得的是一個數組[5,5,5,5,5]。函數
在看解決方案一以前,咱們先看一下匿名函數的自我執行:ui
匿名函數自我執行的寫法是,在函數體外面加一對圓括號,造成一個表達式,在圓括號後面再加一個圓括號,裏面可傳入參數。code
例以下代碼:htm
(function(){ alert('lee'); //匿名函數自我執行(匿名函數)() })();
咱們再來看解決方案1:blog
function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = (function(num){ //自我執行,並傳參(將匿名函數造成一個表達式)(傳遞一個參數) return num; //這裏的num寫什麼均可以 })(i); //這時候這個括號裏面的i和上面arr[i]的值是同樣的都是取自for循環裏面的i } return arr; } //alert(box()); //alert(box()[1]); //alert(box().length); alert(box()[0]);
經過給匿名函數傳參,而傳遞的這個參數i是每次執行for循環裏面的i,每次傳遞的參數i的值都不同,匿名函數裏面的num接收傳遞的參數i,因此box()最終輸出結果爲[0,1,2,3,4]ip
這種方案的原理就是在匿名函數1裏面再寫入一個匿名函數2,這個匿名函數2須要的num值會在他的父級函數匿名函數1裏面去尋找,而匿名函數1裏面的num值就是傳入的這個參數i,和上面例子中的i是同樣的,
function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = (function(num){ //num在這裏 //原理和上面一種方法同樣的,因此能夠實現閉包 return function(){ //在這個閉包裏面再寫一個匿名函數 return num; }; })(i) } return arr; } //alert(box()); //alert(box()[1]); //alert(box().length); var b = box(); alert(b[0]()); alert(box()[0]());
box()最終返回結果[0,1,2,3,4],
若是將一個匿名函數自我執行的時候賦值給一個變量,那麼這個匿名函數中的圓括號的能夠去掉的,看下面代碼,
var tip = function(){ //這樣把匿名函數自我執行的時候賦值給一個變量,那麼圓括號是能夠去掉的 alert('lee'); }();
利用匿名函數的這一特色,咱們能夠將解決方案1中的代碼改進一下:
function box(){ var arr = []; for(var i=0;i<5;i++){ arr[i] = function(num){ return num; }(i); } return arr; } //alert(box()); //alert(box()[1]); //alert(box().length); alert(box()[4]);
匿名函數在執行的時候他自己就傳遞給了一個變量arr[i],因此匿名函數的圓括號是能夠去掉的。