JavaScript中閉包的4個(gè)有用技巧分享
前言
當(dāng)談到JavaScript編程中的高級(jí)概念和技巧時(shí),閉包(Closures)是一個(gè)重要而有趣的主題。閉包是一種函數(shù)與其創(chuàng)建時(shí)的詞法環(huán)境的組合,它允許我們捕獲和保留局部變量,并在函數(shù)之外使用它們。在這篇文章中,我們將深入探討JavaScript中閉包的4種有用技巧,以及如何應(yīng)用它們來(lái)解決各種問(wèn)題和提高代碼質(zhì)量。
1. 解決循環(huán)中的問(wèn)題
在JavaScript中,循環(huán)中的變量作用域問(wèn)題經(jīng)常會(huì)導(dǎo)致預(yù)期之外的結(jié)果。通常,使用var聲明變量會(huì)導(dǎo)致循環(huán)中的變量共享相同的作用域,因此在異步操作中,這些變量可能會(huì)具有意外的值。
問(wèn)題場(chǎng)景:
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出什么?
}, 1000 * i);
}
上述代碼將在1秒、2秒和3秒后分別打印出3,三次都是相同的值。這是因?yàn)?code>setTimeout是異步的,它在循環(huán)結(jié)束后才執(zhí)行,此時(shí)i的值已經(jīng)是3。
解決方法:
使用閉包來(lái)保存每次迭代中的i的值:
for (var i = 0; i < 3; i++) {
((n) => {
setTimeout(() => {
console.log(n); // 輸出0、1、2
}, 1000 * n);
})(i);
}
或者,更簡(jiǎn)單的方式是使用let來(lái)聲明循環(huán)變量,它將在每次迭代中創(chuàng)建一個(gè)新的作用域:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 輸出0、1、2
}, 1000 * i);
}
這2種方法都可以解決循環(huán)中的作用域問(wèn)題。
2. 保存函數(shù)狀態(tài)
閉包還可以用于實(shí)現(xiàn)記憶功能,通過(guò)緩存計(jì)算結(jié)果來(lái)提高性能。這在需要重復(fù)計(jì)算的函數(shù)中特別有用。
問(wèn)題場(chǎng)景:
實(shí)現(xiàn)一個(gè)累加器:
let sum = 1;
function add(num) {
sum += num;
return sum;
}
console.log(add(1));
console.log(add(5));
每次調(diào)用add時(shí),它都會(huì)將上次的值保存下來(lái)。但是這段代碼有潛在的問(wèn)題,那就是sum可能會(huì)被其他部分代碼無(wú)意中修改。那如何解決?
解決方法:
使用閉包就可以規(guī)避上面存在的問(wèn)題且可以緩存已經(jīng)計(jì)算的值:
function calculator(val) {
let sum = val;
return function(num) {
sum += num;
return sum;
}
}
const add = calculator(1);
console.log(add(1)); //2
console.log(add(5)); //7
每次調(diào)用返回的函數(shù)時(shí),它都會(huì)將傳遞給它的數(shù)字加到總和中,并返回新的總和。
3. 封裝私有變量和屬性
在過(guò)去,為了保護(hù)對(duì)象的私有變量,常常使用閉包。通過(guò)閉包,可以將變量封裝在函數(shù)內(nèi)部,只能通過(guò)函數(shù)暴露的接口來(lái)訪問(wèn)和修改。
問(wèn)題場(chǎng)景:
function add() {
let count = 0;
count++;
console.log(count);
}
add(); //輸出1
add(); //輸出1
add(); //輸出1
調(diào)用函數(shù),輸出的結(jié)果都是1,但是顯然我們想要的效果是讓count每次加1的。那如何解決呢?
解決方法:
使用閉包來(lái)封裝私有變量:
function add(){
let count = 0;
function a() {
count++;
console.log(count);
}
return a;
}
var res = add();
res() //1
res() //2
res() //3
add函數(shù)返回了一個(gè)閉包a,其中包含了count變量。由于count只在add函數(shù)內(nèi)部定義,因此外部無(wú)法直接訪問(wèn)它。但是,由于a函數(shù)引用了count變量,因此count變量的值可以在閉包內(nèi)部被修改和訪問(wèn),這樣就可以防止它被惡意修改了。
4. 函數(shù)柯里化
函數(shù)柯里化是一種將接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)化為一系列接受一個(gè)參數(shù)的函數(shù)的過(guò)程。這也可以通過(guò)閉包來(lái)實(shí)現(xiàn)。
問(wèn)題場(chǎng)景:
const add = (a, b, c) => {
return a + b + c;
}
console.log(add(2, 3, 4)); // 輸出9
解決方法:
使用閉包來(lái)實(shí)現(xiàn)函數(shù)柯里化:
function curry(callback) {
const args = [];
return function curried(...newArgs) {
args.push(...newArgs);
if (args.length >= callback.length) {
return callback(...args);
} else {
return curried;
}
};
}
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(2)(3)(4)); // 輸出 9
函數(shù)柯里化使函數(shù)更加靈活,能夠逐步接受參數(shù),提高代碼的可重用性和可讀性。
總結(jié)
在本文中,我們深入探討了JavaScript中閉包的4種有用技巧,以及如何應(yīng)用它們來(lái)解決各種問(wèn)題和提高代碼質(zhì)量。這些技巧包括解決循環(huán)中的變量作用域問(wèn)題,實(shí)現(xiàn)記憶功能以提高性能,封裝私有變量和屬性,以及使用函數(shù)柯里化來(lái)提高函數(shù)的靈活性。
閉包是JavaScript中一個(gè)強(qiáng)大的概念,它允許我們?cè)诤瘮?shù)之外訪問(wèn)和操作局部變量,從而解決了許多常見(jiàn)的編程問(wèn)題。雖然閉包在JavaScript中有著廣泛的應(yīng)用,但也需要小心使用,以避免潛在的內(nèi)存泄漏問(wèn)題。確保在不再需要閉包時(shí),及時(shí)釋放對(duì)其的引用,以幫助垃圾回收器正常運(yùn)作。希望本文對(duì)你理解JavaScript中的閉包和如何應(yīng)用它們有所幫助。
以上就是JavaScript中閉包的4個(gè)有用技巧分享的詳細(xì)內(nèi)容,更多關(guān)于JavaScript閉包的有用技巧的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
js使用visibilitychange處理頁(yè)面關(guān)閉事件
本文主要介紹了js使用visibilitychange處理頁(yè)面關(guān)閉事件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
js使用navigator.userAgent判斷當(dāng)前瀏覽器所處的環(huán)境
本文主要介紹了js使用navigator.userAgent判斷當(dāng)前瀏覽器所處的環(huán)境,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
JS前端開(kāi)發(fā)之exec()和match()的對(duì)比使用
match()方法可在字符串內(nèi)檢索指定的值,或找到一個(gè)或多個(gè)正則表達(dá)式的匹配,下面這篇文章主要給大家介紹了關(guān)于JS前端開(kāi)發(fā)之exec()和match()的對(duì)比使用的相關(guān)資料,需要的朋友可以參考下2022-09-09
通過(guò)js給網(wǎng)頁(yè)加上水印背景實(shí)例
這篇文章主要介紹了通過(guò)js給網(wǎng)頁(yè)加上水印背景實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,,需要的朋友可以參考下2019-06-06
LayUi使用switch開(kāi)關(guān),動(dòng)態(tài)的去控制它是否被啟用的方法
今天小編就為大家分享一篇LayUi使用switch開(kāi)關(guān),動(dòng)態(tài)的去控制它是否被啟用的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
html的DOM中document對(duì)象images集合用法實(shí)例
這篇文章主要介紹了html的DOM中document對(duì)象images集合用法,實(shí)例分析了images集合的語(yǔ)法與使用技巧,需要的朋友可以參考下2015-01-01

