97色伦色在线综合视频,无玛专区,18videosex性欧美黑色,日韩黄色电影免费在线观看,国产精品伦理一区二区三区,在线视频欧美日韩,亚洲欧美在线中文字幕不卡

s001網(wǎng)站建設(shè)公司網(wǎng)絡(luò)營銷有什么行業(yè)

鶴壁市浩天電氣有限公司 2026/01/24 12:36:56
s001網(wǎng)站建設(shè)公司,網(wǎng)絡(luò)營銷有什么行業(yè),貴州建設(shè)監(jiān)理網(wǎng)站培訓(xùn)通知欄,wordpress搜索參數(shù)JavaScript學(xué)習(xí)筆記#xff1a;17.閉包 上一篇用模塊搞定了代碼的“部門分工”#xff0c;這一篇咱們來攻克JS中“既神秘又核心”的概念——閉包#xff08;Closures#xff09;。你可能聽過“閉包能保留變量”“閉包會導(dǎo)致內(nèi)存泄漏”#xff0c;但始終沒搞懂它到底是什么…JavaScript學(xué)習(xí)筆記17.閉包上一篇用模塊搞定了代碼的“部門分工”這一篇咱們來攻克JS中“既神秘又核心”的概念——閉包Closures。你可能聽過“閉包能保留變量”“閉包會導(dǎo)致內(nèi)存泄漏”但始終沒搞懂它到底是什么也可能在寫防抖節(jié)流、私有變量時無意中用過它卻不知道背后的原理。其實閉包一點都不玄乎它就像函數(shù)的“帶鑰匙管家”外部函數(shù)相當(dāng)于“主人”執(zhí)行完后作用域本應(yīng)“關(guān)門大吉”但內(nèi)部函數(shù)“管家”偷偷揣著“鑰匙”引用外部函數(shù)的變量即使主人走了管家還能隨時打開門訪問里面的“財物”變量。今天咱們就用“房間與鑰匙”的生活化比喻把閉包的形成原理、實戰(zhàn)用法、優(yōu)缺點和避坑指南徹底講透讓你從“模糊感知”到“熟練運用”。一、先破案為什么需要閉包普通函數(shù)的痛點普通函數(shù)執(zhí)行完后其作用域會被垃圾回收機(jī)制銷毀里面的變量也會隨之消失就像主人出門后房間被清空再回來啥都沒了。但開發(fā)中經(jīng)常需要“保留函數(shù)執(zhí)行后的狀態(tài)”比如計數(shù)器多次調(diào)用函數(shù)累加同一個變量不是每次都從0開始私有變量不想讓外部直接訪問的變量只能通過特定方法操作防抖節(jié)流需要記住上一次執(zhí)行的時間判斷是否觸發(fā)下一次。這些場景普通函數(shù)搞不定而閉包能完美解決——它能讓函數(shù)執(zhí)行后作用域不被銷毀變量被“偷偷保留”下來。看個直觀例子普通函數(shù)vs閉包函數(shù)// 普通函數(shù)執(zhí)行后變量消失無法累加functionnormalCounter(){letcount0;count;returncount;}console.log(normalCounter());// 1console.log(normalCounter());// 1count每次都重新初始化無法累加// 閉包函數(shù)執(zhí)行后變量被保留實現(xiàn)累加functionclosureCounter(){letcount0;// 外部函數(shù)變量// 內(nèi)部函數(shù)引用外部函數(shù)的countreturnfunction(){count;returncount;};}constcounterclosureCounter();// 外部函數(shù)執(zhí)行返回內(nèi)部函數(shù)管家?guī)ц€匙出門console.log(counter());// 1管家開門count1console.log(counter());// 2管家再開門count2console.log(counter());// 3變量被持續(xù)保留核心差異普通函數(shù)的變量隨作用域銷毀閉包的變量被內(nèi)部函數(shù)引用作用域不銷毀變量持續(xù)可用。二、閉包的核心原理什么是閉包怎么形成的1. 閉包的定義MDN官方閉包是指一個函數(shù)以及其捆綁的周邊環(huán)境狀態(tài)lexical environment詞法環(huán)境的引用的組合。簡單說閉包讓內(nèi)部函數(shù)可以訪問外部函數(shù)的作用域即使外部函數(shù)已經(jīng)執(zhí)行完畢。用“房間比喻”翻譯外部函數(shù) 主人的房間外部函數(shù)變量 房間里的財物內(nèi)部函數(shù) 帶鑰匙的管家閉包 管家鑰匙房間的組合即使主人走了管家還能開門取財物。2. 閉包的形成條件缺一不可閉包不是“寫個嵌套函數(shù)就是閉包”必須滿足三個條件函數(shù)嵌套存在內(nèi)部函數(shù)和外部函數(shù)嵌套關(guān)系變量引用內(nèi)部函數(shù)引用了外部函數(shù)的變量/參數(shù)管家拿了鑰匙外部暴露外部函數(shù)執(zhí)行后內(nèi)部函數(shù)被外部引用管家出門了沒被留在房間里。// 滿足三個條件閉包形成functionouter(){constouterVar我是外部變量;// 外部函數(shù)變量functioninner(){console.log(outerVar);// 內(nèi)部函數(shù)引用外部變量條件2}returninner;// 外部暴露內(nèi)部函數(shù)條件3}constinnerFuncouter();// 外部函數(shù)執(zhí)行內(nèi)部函數(shù)被外部引用innerFunc();// 打印我是外部變量閉包生效// 不滿足條件3無閉包內(nèi)部函數(shù)沒被外部引用functionouter2(){constouterVar我是外部變量;functioninner2(){console.log(outerVar);}inner2();// 內(nèi)部函數(shù)在外部函數(shù)內(nèi)執(zhí)行沒被外部引用}outer2();// 執(zhí)行后outer2作用域銷毀無閉包3. 閉包的執(zhí)行過程為什么變量能保留咱們拆解closureCounter的執(zhí)行過程看懂閉包的“魔法”調(diào)用closureCounter()外部函數(shù)執(zhí)行創(chuàng)建外部函數(shù)作用域聲明count0外部函數(shù)返回內(nèi)部函數(shù)此時內(nèi)部函數(shù)引用了count外部函數(shù)執(zhí)行完畢但因為內(nèi)部函數(shù)還引用著它的變量作用域不會被垃圾回收房間沒被清空。調(diào)用counter()內(nèi)部函數(shù)執(zhí)行內(nèi)部函數(shù)執(zhí)行時先在自己的作用域找count找不到順著作用域鏈找到外部函數(shù)的作用域因為閉包保留了引用訪問并修改count實現(xiàn)累加。多次調(diào)用counter()重復(fù)步驟2count持續(xù)被保留和修改。簡單說閉包的本質(zhì)是“作用域鏈的延長”——內(nèi)部函數(shù)的作用域鏈永遠(yuǎn)保留著對外部函數(shù)作用域的引用即使外部函數(shù)執(zhí)行完。三、閉包的實戰(zhàn)場景這些功能離不開閉包閉包不是“炫技工具”而是很多核心功能的底層實現(xiàn)以下三個場景幾乎是前端開發(fā)的“必備技能”。1. 場景1實現(xiàn)私有變量隱藏內(nèi)部狀態(tài)JS沒有原生的私有變量ES6的#私有字段是后來加的閉包是傳統(tǒng)實現(xiàn)“私有變量”的唯一方式——讓變量只能通過特定方法訪問不能被外部直接修改保證數(shù)據(jù)安全。// 用閉包實現(xiàn)“安全的銀行賬戶”私有變量余額functioncreateBankAccount(initialBalance){// 私有變量外部無法直接訪問letbalanceinitialBalance;// 暴露對外接口閉包函數(shù)return{deposit(amount){// 存款只能通過這個方法修改余額if(amount0){balanceamount;return存款成功余額${balance};}return存款金額無效;},withdraw(amount){// 取款只能通過這個方法修改余額if(amount0amountbalance){balance-amount;return取款成功余額${balance};}return取款金額無效;},getBalance(){// 查詢余額只能通過這個方法訪問余額return當(dāng)前余額${balance};}};}// 使用賬戶constaccountcreateBankAccount(1000);console.log(account.getBalance());// 當(dāng)前余額1000console.log(account.deposit(500));// 存款成功余額1500console.log(account.withdraw(300));// 取款成功余額1200// 外部無法直接訪問私有變量console.log(account.balance);// undefined無法直接訪問account.balance100000;// 無效修改的是對象的新屬性不是閉包中的balanceconsole.log(account.getBalance());// 當(dāng)前余額1200余額未變2. 場景2防抖與節(jié)流前端性能優(yōu)化神器防抖debounce和節(jié)流throttle是解決“高頻事件觸發(fā)”如滾動、輸入、點擊的核心方案它們的底層都依賴閉包保留“上次執(zhí)行時間”“計時器ID”等狀態(tài)。1防抖觸發(fā)后延遲n秒執(zhí)行期間再次觸發(fā)則重新計時// 防抖函數(shù)閉包實現(xiàn)functiondebounce(fn,delay){lettimerId;// 閉包保留計時器IDreturnfunction(...args){// 再次觸發(fā)時清除之前的計時器clearTimeout(timerId);// 重新設(shè)置計時器延遲執(zhí)行timerIdsetTimeout((){fn.apply(this,args);// 執(zhí)行原函數(shù)},delay);};}// 用法輸入框搜索避免輸入時頻繁請求接口constsearchInputdocument.querySelector(input);functionsearch(keyword){console.log(搜索${keyword});// 實際開發(fā)中這里是接口請求}// 給搜索函數(shù)加防抖延遲500msconstdebouncedSearchdebounce(search,500);searchInput.addEventListener(input,(e){debouncedSearch(e.target.value);});閉包在這里的作用保留timerId讓每次觸發(fā)時都能訪問到上一次的計時器實現(xiàn)“清除舊計時器、設(shè)置新計時器”。2節(jié)流n秒內(nèi)只執(zhí)行一次避免頻繁觸發(fā)// 節(jié)流函數(shù)閉包實現(xiàn)functionthrottle(fn,interval){letlastTime0;// 閉包保留上次執(zhí)行時間returnfunction(...args){constcurrentTimeDate.now();// 距離上次執(zhí)行時間超過interval才執(zhí)行if(currentTime-lastTimeinterval){fn.apply(this,args);lastTimecurrentTime;// 更新上次執(zhí)行時間}};}// 用法滾動事件避免滾動時頻繁觸發(fā)functionhandleScroll(){console.log(滾動觸發(fā));// 實際開發(fā)中這里是滾動加載、位置計算等}// 給滾動函數(shù)加節(jié)流1秒內(nèi)只執(zhí)行一次constthrottledScrollthrottle(handleScroll,1000);window.addEventListener(scroll,throttledScroll);3. 場景3函數(shù)工廠批量生成帶狀態(tài)的函數(shù)用閉包批量生成具有相同邏輯但不同狀態(tài)的函數(shù)比如批量生成“帶固定前綴的日志函數(shù)”“帶特定權(quán)限的接口請求函數(shù)”。// 函數(shù)工廠生成帶固定前綴的日志函數(shù)functioncreateLogger(prefix){// 閉包保留前綴returnfunction(message){consttimenewDate().toLocaleTimeString();console.log([${prefix}][${time}]${message});};}// 批量生成不同類型的日志函數(shù)constinfoLoggercreateLogger(INFO);consterrorLoggercreateLogger(ERROR);constwarnLoggercreateLogger(WARN);// 使用infoLogger(用戶登錄成功);// [INFO][14:30:00] 用戶登錄成功errorLogger(接口請求失敗);// [ERROR][14:30:05] 接口請求失敗warnLogger(參數(shù)格式錯誤);// [WARN][14:30:10] 參數(shù)格式錯誤每個日志函數(shù)都保留著自己的prefix邏輯相同但狀態(tài)獨立這就是閉包的“狀態(tài)隔離”能力。四、閉包的優(yōu)缺點一把“雙刃劍”閉包很強(qiáng)大但不是萬能的它是一把“雙刃劍”有優(yōu)點也有需要警惕的缺點。1. 優(yōu)點保留狀態(tài)函數(shù)執(zhí)行后保留變量實現(xiàn)累加、緩存等功能數(shù)據(jù)私有隱藏內(nèi)部變量只暴露指定接口保證數(shù)據(jù)安全邏輯復(fù)用批量生成帶狀態(tài)的函數(shù)減少重復(fù)代碼。2. 缺點重點避坑內(nèi)存泄漏風(fēng)險閉包引用的外部函數(shù)變量不會被垃圾回收若長期不釋放會占用額外內(nèi)存嚴(yán)重時導(dǎo)致內(nèi)存泄漏調(diào)試?yán)щy閉包延長了作用域鏈變量的生命周期變得復(fù)雜調(diào)試時難以追蹤變量的修改路徑。五、避坑指南正確使用閉包避免踩雷1. 避坑1避免不必要的閉包及時釋放引用不需要保留狀態(tài)時不要用閉包閉包不用時手動解除引用讓垃圾回收機(jī)制回收變量// 反面例子長期持有閉包不釋放constcounterclosureCounter();// ... 不再使用counter但沒有解除引用// 閉包中的count會一直存在占用內(nèi)存// 正面例子不用時解除引用letcounterclosureCounter();counter();// 使用counternull;// 解除引用閉包中的變量會被垃圾回收2. 避坑2循環(huán)中的閉包陷阱經(jīng)典面試題這是閉包最經(jīng)典的坑用var聲明循環(huán)變量閉包會引用同一個變量導(dǎo)致所有內(nèi)部函數(shù)執(zhí)行時拿到的都是最后一個值。// 反面例子循環(huán)中的閉包陷阱constarr[];for(vari0;i3;i){arr.push(function(){console.log(i);// 內(nèi)部函數(shù)引用循環(huán)變量ivar聲明全局作用域});}// 執(zhí)行數(shù)組中的函數(shù)arr[0]();// 3arr[1]();// 3arr[2]();// 3所有函數(shù)拿到的都是i的最終值3原因var聲明的i是全局變量循環(huán)中所有內(nèi)部函數(shù)引用的都是同一個i循環(huán)結(jié)束后i3所以執(zhí)行時都打印3。解決方案用let聲明循環(huán)變量let有塊級作用域每次循環(huán)都會創(chuàng)建新的i用立即執(zhí)行函數(shù)IIFE創(chuàng)建獨立作用域。// 解決方案1用let聲明推薦constarr[];for(leti0;i3;i){arr.push(function(){console.log(i);// 每個函數(shù)引用的是當(dāng)前循環(huán)的i塊級作用域});}arr[0]();// 0arr[1]();// 1arr[2]();// 2// 解決方案2用IIFE兼容舊環(huán)境constarr[];for(vari0;i3;i){(function(j){arr.push(function(){console.log(j);// 每個函數(shù)引用的是IIFE的參數(shù)j獨立作用域});})(i);// 立即執(zhí)行傳入當(dāng)前i的值}arr[0]();// 0arr[1]();// 1arr[2]();// 23. 避坑3閉包不要引用過大的變量閉包會保留外部函數(shù)的整個作用域而不是只保留引用的變量。如果外部函數(shù)有很多大變量比如大數(shù)組、大對象即使內(nèi)部函數(shù)只引用了一個小變量整個作用域的變量都會被保留導(dǎo)致內(nèi)存浪費。// 反面例子閉包引用外部函數(shù)的大變量functionouter(){constbigDatanewArray(1000000).fill(0);// 大數(shù)組占用大量內(nèi)存constsmallVar我只需要這個;returnfunction(){console.log(smallVar);// 只引用了smallVar但bigData也會被保留};}// 正面例子只保留需要的變量避免引用大變量functionouter(){constsmallVar我只需要這個;// 大變量放在不需要的地方或手動釋放constbigDatanewArray(1000000).fill(0);bigDatanull;// 手動釋放大變量returnfunction(){console.log(smallVar);};}六、總結(jié)閉包的核心價值與本質(zhì)閉包的本質(zhì)是“作用域鏈的延長與保留”核心價值是“讓函數(shù)突破作用域的限制保留執(zhí)行狀態(tài)”。它不是JS的“特殊功能”而是作用域和作用域鏈的自然產(chǎn)物——只要滿足“嵌套函數(shù)、引用外部變量、外部暴露內(nèi)部函數(shù)”三個條件閉包就會自動形成。記住三個核心點閉包是“帶鑰匙的管家”保留外部函數(shù)的變量即使外部函數(shù)執(zhí)行完閉包的核心用法私有變量、防抖節(jié)流、函數(shù)工廠閉包的使用原則按需使用及時釋放避免引用過大變量和循環(huán)陷阱。閉包是JS的“進(jìn)階門檻”掌握它不僅能寫出更優(yōu)雅、更安全的代碼還能理解很多前端框架和工具的底層實現(xiàn)比如React的hooks、Vue的響應(yīng)式。下一篇筆記咱們會聊JS的“異步進(jìn)階”——Async/Await解鎖更簡潔的異步編程方式。
版權(quán)聲明: 本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請聯(lián)系我們進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

高校信息公開網(wǎng)站建設(shè)wordpress get attachment

高校信息公開網(wǎng)站建設(shè),wordpress get attachment,搜索網(wǎng)站不顯示圖片,門戶網(wǎng)站建設(shè)自查整改報告“技術(shù)迭代太快#xff0c;剛學(xué)會的框架已經(jīng)過時了?!薄耙粋€人開發(fā)#xff0c;從產(chǎn)

2026/01/23 15:02:01

網(wǎng)站建設(shè)兩個方面齊齊哈爾北京網(wǎng)站建設(shè)

網(wǎng)站建設(shè)兩個方面,齊齊哈爾北京網(wǎng)站建設(shè),備案號怎么放到網(wǎng)站,小程序定制開發(fā)目錄 具體實現(xiàn)截圖項目介紹論文大綱核心代碼部分展示項目運行指導(dǎo)結(jié)論源碼獲取詳細(xì)視頻演示 #xff1a;文章底部獲取博主聯(lián)系方式

2026/01/23 16:44:01

做網(wǎng)站圖片教程網(wǎng)頁掛馬

做網(wǎng)站圖片教程,網(wǎng)頁掛馬,房屋設(shè)計師,做外貿(mào)公司網(wǎng)站UNIX/Linux 編程:Awk 與 Perl 實戰(zhàn)指南 1. Awk 語言基礎(chǔ)與實際應(yīng)用 1.1 鐵路公司數(shù)據(jù)處理問題 假設(shè)有一家鐵路公司

2026/01/23 07:15:01

網(wǎng)站建設(shè)主頁孝感市門戶網(wǎng)

網(wǎng)站建設(shè)主頁,孝感市門戶網(wǎng),skxy wordpress,如何用花生殼做網(wǎng)站在數(shù)據(jù)采集領(lǐng)域#xff0c;增量更新是提升爬蟲效率、降低目標(biāo)服務(wù)器壓力的核心技術(shù)手段。相比于全量爬取#xff0c;增量更新僅

2026/01/23 01:52:02