這篇文章主要介紹了JavaScript閉包實(shí)例代碼分析的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇JavaScript閉包實(shí)例代碼分析文章都會(huì)有所收獲,下面我們一起來(lái)看看吧。
成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括陳巴爾虎網(wǎng)站建設(shè)、陳巴爾虎網(wǎng)站制作、陳巴爾虎網(wǎng)頁(yè)制作以及陳巴爾虎網(wǎng)絡(luò)營(yíng)銷(xiāo)策劃等。多年來(lái),我們專(zhuān)注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,陳巴爾虎網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到陳巴爾虎省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
閉包的概念是有很多版本,不同的地方對(duì)閉包的說(shuō)法不一
維基百科:在計(jì)算機(jī)科學(xué)中,閉包(英語(yǔ):Closure),又稱(chēng)詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是在支持頭等函數(shù)的編程語(yǔ)言中實(shí)現(xiàn)詞法綁定的一種技術(shù)。
MDN: 閉包(closure)是一個(gè)函數(shù)以及其捆綁的周邊環(huán)境狀態(tài)(lexical environment,詞法環(huán)境)的引用的組合。
個(gè)人理解:
閉包是一個(gè)函數(shù)(返回一個(gè)函數(shù))
返回的函數(shù)保存了對(duì)外變量引用
function fn() { let num = 1; return function (n) { return n + num
}
}let rFn = fn()let newN = rFn(3) // 4
num 變量作用域在 fn 函數(shù)中, rFn 函數(shù)卻能訪問(wèn) num 變量,這就是閉包函數(shù)能訪問(wèn)外部函數(shù)變量。
瀏覽器
VS Code 配合 Node.js
看到 Closure 中 fn 是閉包函數(shù),其中保存 num 變量。
for (var i = 1; i <= 5; i++) { setTimeout(() => { console.log(i);
}, i * 1000);
}
輸出的結(jié)果都是 6,為什么?
for 循環(huán)是同步任務(wù)
setTimeout 異步任務(wù)
for 循環(huán)一次,就會(huì)將 setTimeout 異步任務(wù)加入到瀏覽器的異步任務(wù)隊(duì)列中,同步任務(wù)完成之后,再?gòu)漠惒饺蝿?wù)中拿新任務(wù)在線程中執(zhí)行。由于 setTimeout 能夠訪問(wèn)外部變量 i, 當(dāng)同步任務(wù)完成之后,i 已經(jīng)變成了6, setTimeout 中能夠訪問(wèn)變量 i 都是 6。
for (var i = 1; i <= 5; i++) { setTimeout(() => { console.log(i);
}, i * 1000);
}
for (var i = 1; i <= 5; i++) {
(function(i){ setTimeout(() => { console.log(i);
}, i * 1000)
})(i)
}
第三個(gè)參數(shù)意思:附加參數(shù),一旦定時(shí)器到期,它們會(huì)作為參數(shù)傳遞給要執(zhí)行的函數(shù)
for (var i = 1; i <= 5; i++) { setTimeout((j) => { console.log(j);
}, 1000 * i, i);
}
function add(num) { return function (y) { return num + y;
};
};let incOneFn = add(1); let n = incOneFn(1); // 2let decOneFn = add(-1); let m = decOneFn(1); // 0
add 函數(shù)的參數(shù)
保存了閉包函數(shù)變量。
在函數(shù)式編程閉包有非常重要的作用,lodash 等早期工具函數(shù)彌補(bǔ) javascript 缺陷的工具函數(shù),有大量的閉包的使用場(chǎng)景。
創(chuàng)建私有變量
延長(zhǎng)變量生命周期
防止?jié)L動(dòng)行為,過(guò)度執(zhí)行函數(shù),必須要節(jié)流, 節(jié)流函數(shù)接受 函數(shù)
+ 時(shí)間
作為參數(shù),都是閉包中變量,以下是一個(gè)簡(jiǎn)單 setTimeout 版本:
function throttle(fn, time=300){ var t = null; return function(){ if(t) return;
t = setTimeout(() => {
fn.call(this);
t = null;
}, time);
}
}
一個(gè)簡(jiǎn)單的基于 setTimeout 防抖的函數(shù)的實(shí)現(xiàn)
function debounce(fn,wait){ var timer = null; return function(){ if(timer !== null){ clearTimeout(timer);
}
timer = setTimeout(fn,wait);
}
}
問(wèn)題說(shuō)明:父/子
組件關(guān)系, 父子組件都能使用 click 事件同時(shí)修改 state 數(shù)據(jù), 并且子組件拿到傳遞下的 props 事件屬性,是經(jīng)過(guò) useCallback
優(yōu)化過(guò)的。也就是這個(gè)被優(yōu)化過(guò)的函數(shù),存在閉包陷阱,(保存一直是初始 state 值)
import { useState, useCallback, memo } from "react";const ChildWithMemo = memo((props: any) => { return (
ChildWithMemo 使用 memo 進(jìn)行優(yōu)化,
handleClickWithUseCallback 使用 useCallback 優(yōu)化
問(wèn)題是點(diǎn)擊子組件時(shí)候,輸出的 count 是初始值(被閉包了)。
解決辦法就是使用 useRef 保存操作變量函數(shù):
import { useState, useCallback, memo, useRef } from "react";const ChildWithMemo = memo((props: any) => { console.log("rendered children") return (
針對(duì)這個(gè)問(wèn)題,React 曾經(jīng)認(rèn)可過(guò)社區(qū)提出的增加 useEvent 方案,但是后面 useEvent 語(yǔ)義問(wèn)題被廢棄了,對(duì)于渲染優(yōu)化 React 采用了編譯優(yōu)化的方案。其實(shí)類(lèi)似的問(wèn)題也會(huì)發(fā)生在 useEffect 中,使用時(shí)要注意閉包陷阱。
閉包不要隨意定義,定義了一定找到合適的位置進(jìn)行銷(xiāo)毀。因?yàn)殚]包的變量保存在內(nèi)存中,不會(huì)被銷(xiāo)毀,占用較高的內(nèi)存。
打開(kāi)開(kāi)發(fā)者工具,選擇 Timeline 面板
在頂部的
Capture
字段里面勾選 Memory點(diǎn)擊左上角的錄制按鈕。
在頁(yè)面上進(jìn)行各種操作,模擬用戶的使用情況。
一段時(shí)間后,點(diǎn)擊對(duì)話框的 stop 按鈕,面板上就會(huì)顯示這段時(shí)間的內(nèi)存占用情況。
關(guān)于“JavaScript閉包實(shí)例代碼分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“JavaScript閉包實(shí)例代碼分析”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。