很長一段時(shí)間不理解閉包,后來了解了作用域,以及 this 相關(guān)問題才理解了閉包相關(guān)知識(shí)。
閉包(closure),也是面試題常客。簡單點(diǎn)來說就是函數(shù)嵌套函數(shù)。 函數(shù)作為返回值:
[js] view plaincopy
function foo () {
var a = 1;
return function () {
a++;
console.log(a);
}
}
var aaa = foo();
aaa(); //2
aaa(); //3
其實(shí)這個(gè)代碼不難理解,aaa 是指向 foo() 返回的一個(gè)新函數(shù),但是在這個(gè)函數(shù)里面引用了 a變量,所以當(dāng)執(zhí)行完 foo 函數(shù)時(shí),變量 a 還存在內(nèi)存中不釋放。即 a 分別為2和3。
函數(shù)作為參數(shù):
[js] view plaincopy
var a = 10;
function foo () {
console.log(a);
}
function aaa(fn) {
var a = 100;
fn();
}
aaa(foo);
按照我以前的理解,當(dāng)執(zhí)行在 aaa 函數(shù)里面執(zhí)行 fn 函數(shù),那么如果自身沒有 a 變量,就去父級(jí)作用域找 a 變量,此處是100,那結(jié)果是100嗎?
可惜答案不是,在這里結(jié)果是10,王福朋老師的博客講的比較好,他說要去創(chuàng)建這個(gè)函數(shù)的作用域取值,而不是“父作用域”。
因?yàn)楸救诉€比較菜鳥,在這里取一個(gè)簡單例子。當(dāng)點(diǎn)擊 li 的時(shí)候彈出 li 在 ul 中所處的位置即索引值。
html代碼:
[xhtml] view plaincopy
<ul>
<li>001</li>
<li>002</li>
<li>003</li>
</ul>
js代碼:
示例 1:
請(qǐng)看下面的代碼,運(yùn)行后發(fā)現(xiàn),無論點(diǎn)擊那個(gè)li,結(jié)果都是3了。
[js] view plaincopy
var aLi = document.getElementsByTagName('li');
for (var i = 0; i<aLi.length; i++) {
aLi[i].onclick = function() {
alert(i);
}
}
因?yàn)樵谀涿瘮?shù)里面并沒有 i 變量,所以當(dāng) for 結(jié)束后,我們?cè)偃c(diǎn)擊頁面的 li 標(biāo)簽,此時(shí)i 早就是3了。
示例 2:
[js] view plaincopy
aLi[i].onclick = (function(i){
return function(){
alert(i);
}
})(i);
這次的做法是把函數(shù)當(dāng)返回值,通過自執(zhí)行函數(shù)的參數(shù),把變量 i 傳進(jìn)去,然后因?yàn)榉祷睾瘮?shù)要引用這個(gè) i 變量,所以當(dāng) for 循環(huán)結(jié)束也不會(huì)釋放 i 變量。即在內(nèi)存中保存了 i 變量的值?;谶@樣的原理,很容易在低版本 ie 中造成內(nèi)存泄露。
示例 3:
[js] view plaincopy
for (var i = 0; i<aLi.length; i++) {
(function(i){
aLi[i].onclick = function(){
alert(i);
}
})(i);
}
這個(gè)原理和上面大同小異。
小米前端閉包面試題:
[js] view plaincopy
function repeat (func, times, wait) {
} //這個(gè)函數(shù)能返回一個(gè)新函數(shù),比如這樣用
var repeatedFun = repeat(alert, 10, 5000)
//調(diào)用這個(gè) repeatedFun ("hellworld")
//會(huì)alert十次 helloworld, 每次間隔5秒
我的答案:
[js] view plaincopy
function repeat (func, times, wait) {
return function(str) {
while (times >0) {
setTimeout(function(){
func(str);
},wait);
times--;
}
}
}
var repeatedFun = repeat(alert, 10, 100);
repeatedFun ("hellworld");
以上所述就是本文的全部內(nèi)容了,希望對(duì)大家學(xué)習(xí) javascript 閉包能夠有所幫助。