閉包,一個近乎神話的概念,對於那些有一點javascript使用經驗但從未真正理解閉包概念的人來講,理解閉包能夠看作是某種意義上的重生,可是須要付出很是多的努力才能理解這個概念,今天咱們經過簡單示例來理解一下神閉包。
// 最簡單的閉包示例 function foo(){ var a = 2; function bar(){ console.log(a); } return bar; } var baz = foo(); baz(); // 2 ----朋友,這就是閉包效果 // 傳遞函數的閉包效果 function foo(){ var a = 2; function baz(){ console.log(a); } bar(baz); } function bar(fn){ fn(); // 媽呀快看啊,這就是閉包效果 } // 傳遞函數固然也能夠是間接的 var fn; function foo(){ var a = 2; function baz(){ console.log(a); } fn = baz; } function bar(){ fn(); // 媽呀快看啊,這就是閉包效果 } foo(); bar(); // 2 // 到處都是閉包,延時器方法來演示閉包 function wait(message){ setTimeout(function timer(){ console.log(message); }, 1000); } wait("hello,closure!"); //將一個內部函數(名爲timer)傳遞給setTimeout(..)。timer具備涵蓋wait(..)做用域的閉包。所以還保有對變量message的引用。 //wait(..)執行1000毫秒後,它的內部做用域並不會消失,timer函數依然保有wait(..)做用域的閉包。 //深刻到引擎的內部原理中,內置的工具函數setTimeout(..)持有對一個參數的引用,這個參數也許叫作fn或者func,或者其餘相似的名字。 //引擎會調用這個函數,在例子中就是內部的timer函數,而詞法做用域在這個過程當中保持完整。 //這就是閉包。 // 循環和閉包 // 要說明閉包,for循環是最多見的例子。 for(var i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); }, i*1000); } // 正常狀況下,咱們對這段代碼行爲的預期是分別輸出數字1~5,每秒一次,每次一個。 // 但實際上,這段代碼在運行時會以每秒一次的頻率輸出五次6. // 仔細想一想緣由,關鍵在於延遲函數的回調會在循環結束時才執行,而當循環結束後,i的值已經變爲了6 // 咱們能夠看看最終運行的順序是下面這樣的 setTimeout(function timer(){ console.log(6); }, 1*1000); setTimeout(function timer(){ console.log(6); }, 2*1000); setTimeout(function timer(){ console.log(6); }, 3*1000); setTimeout(function timer(){ console.log(6); }, 4*1000); setTimeout(function timer(){ console.log(6); }, 5*1000); // 想要實現咱們要的效果,實際上須要給回調函數一個獨立的i的副本,這樣i的值變化,就不會影響回調函數執行中得副本值了 for(var i=1;i<=5;i++){ (function(){ var j = i; setTimeout(function timer(){ console.log(j); }, j*1000); })(); } // 或者以下寫法也能夠 for(var i=1;i<=5;i++){ (function(j){ setTimeout(function timer(){ console.log(j); }, j*1000); })(i); } // 重返塊做用域,let關鍵字能夠實現,但由於目前對瀏覽器的支持不夠,支持javascript1.8版本以上的瀏覽器才能夠,因此咱們建議非特殊狀況,不使用這個關鍵字 for(var i=1;i<=5;i++){ let j=i; setTimeout(function timer(){ console.log(j); }, j*1000); } //或者更簡單寫法 for(let i=1;i<=5;i++){ setTimeout(function timer(){ console.log(i); }, i*1000); } //正確的效果的運行順序以下: setTimeout(function timer(){ console.log(1); }, 1*1000); setTimeout(function timer(){ console.log(2); }, 2*1000); setTimeout(function timer(){ console.log(3); }, 3*1000); setTimeout(function timer(){ console.log(4); }, 4*1000); setTimeout(function timer(){ console.log(5); }, 5*1000);
經過這幾個簡單示例,對閉包有了初步瞭解,閉包到處都在,在意咱們如何觀察和理解
更多信息能夠看看個人博文,並下載相關資料