閉包和高階函數(shù)
- 函數(shù)式語言的鼻祖是 LISP
- JavaScript在設(shè)計(jì)之初參考了 LISP兩大方言之一的 Scheme关顷,引入了 Lambda表達(dá)式邢享、閉包、高階函數(shù)等特性脚粟。
閉包
閉包的形成與變量的作用域以及變量的生存周期密切相關(guān)覆旱。
變量的作用域
- 變量的作用域,就是指變量的有效范圍核无。
- 變量的搜索是從內(nèi)到外而非從外到內(nèi)的扣唱。
變量的生命周期
- 對于全局變量來說,全局變量的生存周期當(dāng)然是永久的厕宗,除非我們主動銷毀這個(gè)全局變量画舌。
- 對于局部變量來說,當(dāng)退出函數(shù)時(shí)已慢,它們都會隨著函數(shù)調(diào)用的結(jié)束而被銷毀曲聂。
var foo = function() {
var a = 1;
return function() {
a++;
alert(a);
}
};
var f = foo();
f(); // 輸出:2
f(); // 輸出:3
f(); // 輸出:4
f(); // 輸出:5
變量
f
返回了一個(gè)匿名函數(shù)的引用,它可以訪問到foo()
被調(diào)用時(shí)產(chǎn)生的環(huán)境佑惠,而局部變量a
一直處在這個(gè)環(huán)境里朋腋。既然局部變量所在的環(huán)境還能被外界訪問,這個(gè)局部變量就有了不被銷毀的理由膜楷。在這里產(chǎn)生了一個(gè)閉包結(jié)構(gòu)旭咽,局部變量的生命看起來被延續(xù)了。
另一個(gè)經(jīng)典例子赌厅,我們通過循環(huán)來給每個(gè) div 綁定 onclick 事件穷绵,按照索引順序,點(diǎn)擊第 1個(gè) div 時(shí)彈出0特愿,點(diǎn)擊第 2個(gè) div 時(shí)彈出 1仲墨,以此類推。
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
var nodes = document.getElementsByTagName( 'div' );
for ( var i = 0, len = nodes.length; i < len; i++ ){
nodes[ i ].onclick = function(){
alert ( i );
}
};
把每次循環(huán)的 i 值都封閉起來揍障。當(dāng)在事件函數(shù)中順著作用域鏈中從內(nèi)到外查找變量 i 時(shí)目养,會先找到被封閉在閉包環(huán)境中的 i
閉包的更多作用
封裝變量
閉包可以幫助把一些不需要暴露在全局的變量封裝成“私有變量”。
var mult = function() {
var a = 2;
for (var i = 0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
}
return a;
};
console.log(mult(1, 2, 3)); //輸出 12