Javascript學(xué)習(xí)筆記之 函數(shù)篇(三) : 閉包和引用
Javascript 中一個(gè)最重要的特性就是閉包的使用。因?yàn)殚]包的使用,當(dāng)前作用域總可以訪問外部的作用域。因?yàn)?Javascript 沒有塊級作用域,只有函數(shù)作用域,所以閉包的使用與函數(shù)是緊密相關(guān)的。
模擬私有變量
function Counter(start) {
var count = start;
return {
increment: function() {
count++;
},
get: function() {
return count;
}
}
}
var foo = Counter(4);
foo.increment();
foo.get(); // 5
這里 Counter 返回兩個(gè)閉包:函數(shù) increment 和 get。這兩個(gè)函數(shù)一直保持著對 Counter 作用域的訪問,因此它們能一直訪問到定義在 Counter 作用域的變量 count。
私有變量的工作機(jī)制
由于 Javascript 不可以對作用域賦值和引用,所以在上例中,是沒有辦法在外部直接訪問內(nèi)部私有變量 count。唯一的方法就是通過定義閉包來訪問。
var foo = new Counter(4);
foo.hack = function() {
count = 1337;
};
上面的代碼不會(huì)改變 Counter 作用域內(nèi)的 count 變量值,因?yàn)?hack 沒有在 Counter 內(nèi)定義。上面這段代碼只會(huì)創(chuàng)建或者覆蓋全局變量 count。
循環(huán)內(nèi)的閉包
一個(gè)最容易犯的錯(cuò)誤就是在循環(huán)內(nèi)使用閉包。
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
上面這段代碼不會(huì)輸出0到9,而是連續(xù)輸出10次10。
上面的匿名會(huì)一直保持一個(gè)對變量 i 的引用。當(dāng)調(diào)用 console.log 函數(shù)開始輸出時(shí),這是循環(huán)已經(jīng)結(jié)束,而變量 i 已經(jīng)為10了。
為了避免上面的錯(cuò)誤發(fā)生,我們需要在每次循環(huán)時(shí)為變量 i 值創(chuàng)建一個(gè)拷貝。
避免引用錯(cuò)誤
為了復(fù)制循環(huán)中變量的值,最好的方式是在外層加一個(gè)匿名的立刻執(zhí)行函數(shù)。
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
這個(gè)外部的匿名函數(shù)接收循環(huán)變量 i 作為第一個(gè)參數(shù),并將其值拷貝至它自身的參數(shù) e。
外部的匿名函數(shù)將參數(shù) e 再傳遞給 setTimeout,因此 setTimeout 有了指向參數(shù) e 的引用。而且這個(gè)參數(shù) e 的值不會(huì)因?yàn)橥獠康难h(huán)改變而改變。
還有另外一個(gè)方法可以實(shí)現(xiàn)同樣的效果,就是在 setTimeout 內(nèi)的匿名函數(shù)中再返回一個(gè)匿名函數(shù):
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}
此外,通過 bind 方法也可以實(shí)現(xiàn)。
for(var i = 0; i < 10; i++) {
setTimeout(console.log.bind(console, i), 1000);
}
文章最后我們來總結(jié)下:
(1)閉包是一種設(shè)計(jì)原則,它通過分析上下文,來簡化用戶的調(diào)用,讓用戶在不知曉的情況下,達(dá)到他的目的;
(2)網(wǎng)上主流的對閉包剖析的文章實(shí)際上是和閉包原則反向而馳的,如果需要知道閉包細(xì)節(jié)才能用好的話,這個(gè)閉包是設(shè)計(jì)失敗的;
(3)盡量少學(xué)習(xí)。
- js函數(shù)的引用, 關(guān)于內(nèi)存的開銷
- 淺談JavaScript 函數(shù)參數(shù)傳遞到底是值傳遞還是引用傳遞
- 菜鳥學(xué)習(xí)JavaScript小實(shí)驗(yàn)之函數(shù)引用
- JavaScript對象參數(shù)的引用傳遞
- Js從頭學(xué)起(基本數(shù)據(jù)類型和引用類型的參數(shù)傳遞詳細(xì)分析)
- js中判斷Object、Array、Function等引用類型對象是否相等
- JavaScript 類的定義和引用 JavaScript高級培訓(xùn) 自定義對象
- javascript引用對象的方法
- JavaScript對象引用與賦值實(shí)例詳解
- javascript引用對象的方法代碼
- js中值引用和地址引用實(shí)例分析
相關(guān)文章
JavaScript字符串對象的concat方法實(shí)例(用于連接兩個(gè)或多個(gè)字符串)
這篇文章主要介紹了JavaScript字符串對象的concat方法實(shí)例,這個(gè)方法用于連接兩個(gè)或多個(gè)字符串,平時(shí)用+號比較多,所以這個(gè)方法可能不太常用,需要的朋友可以參考下2014-10-10JavaScript 鼠標(biāo)事件(MouseEvent)案例講解
這篇文章主要介紹了JavaScript 鼠標(biāo)事件(MouseEvent)案例講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08淺談JavaScript中setInterval和setTimeout的使用問題
這篇文章主要介紹了淺談JavaScript中setInterval和setTimeout的使用問題,作者建議在任務(wù)龐大時(shí)盡量避免使用setInterval,需要的朋友可以參考下2015-08-08總結(jié)javascript三元運(yùn)算符知識(shí)點(diǎn)
這是一篇關(guān)于javascript三元運(yùn)算符的相關(guān)基礎(chǔ)知識(shí)點(diǎn)內(nèi)容,大家可以學(xué)習(xí)一下鞏固基礎(chǔ)知識(shí)。2018-09-09