工做中大量的使用javascript,可是卻並理解閉包是什麼?總感受這門語言有其隱蔽的一面,若是可以掌握將會千米大增。javascript
閉包是基於詞法做用域書寫代碼時產生的天然結果,其實閉包在日常書寫的js代碼中隨處可見。java
當函數能夠記住並訪問所在的詞法做用域時,就產生了閉包,即便函數是在當前詞法做用域以外執行閉包
PS:我對其的理解是當一段詞法做用域的代碼執行以後,js引擎會對其進行回收,以便來提升性能,可是閉包阻止了這種回收,使這段詞法做用域依舊處在內存當中,當你調用詞法做用域中的局部變量時,依舊存在。函數
下面咱們來看一段代碼,清晰地展現了閉包:性能
function foo(){spa
var a = 2;ip
function bar(){內存
console.log(a);作用域
}回調函數
return bar;
}
var baz = foo();
baz(); //2 ----這就是閉包的效果
在 foo() 執行後,一般會期待 foo() 的整個內部做用域都被銷燬,由於咱們知道引擎有垃圾回收器用來釋放再也不使用的內存空間。因爲看上去 foo() 的內容不會再被使用,因此很 天然地會考慮對其進行回收。 而閉包的「神奇」之處正是能夠阻止這件事情的發生。事實上內部做用域依然存在,所以 沒有被回收。
function wait(message) {
setTimeout( function timer() {
console.log( message );
}, 1000 );
}
wait( "Hello, closure!" );
wait(..) 執行 1000 毫秒後,它的內部做用域並不會消失,timer 函數依然保有 wait(..) 做用域的閉包。
要說明閉包,for 循環是最多見的例子。
for (var i=1; i<=5; i++) {
setTimeout( function timer() { console.log( i );
}, i*1000 );
}
正常狀況下,咱們對這段代碼行爲的預期是分別輸出數字 1~5,每秒一次,每次一個。
但實際上,這段代碼在運行時會以每秒一次的頻率輸出五次 6。
事實上, 當定時器運行時即便每一個迭代中執行的是 setTimeout(.., 0),全部的回調函數依然是在循 環結束後纔會被執行,所以會每次輸出一個 6 出來。
正確的作法是,咱們要使用閉包,首先按照定義咱們要給每次循環一個詞法做用域,每一個做用域都要有本身的i的值,以下:
for(var i =1; i<=5;i++){
(function(i){ //給每次循環一個獨立的詞法做用域
setTimeout(function(){
console.log(i);
},i*1000);
})(i);
}
固然在ES6中,能夠用let聲明:
for (let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}