
文章目錄JavaScript 閉包定義三大特性用法數(shù)據(jù)私有化函數(shù)工廠防抖節(jié)流內(nèi)存泄露問題場景一長期緩存場景二未解綁DOM事件監(jiān)聽場景三未清理定時器JavaScript 閉包定義閉包 內(nèi)部函數(shù) 持有外部函數(shù)作用域的引用函數(shù)嵌套內(nèi)層函數(shù)引用外層函數(shù)作用域里的變量內(nèi)層函數(shù)被外層函數(shù)持有如return出去functionouter(){letcount0// 外層函數(shù)的變量functioninner(){count// 內(nèi)層函數(shù)引用外層函數(shù)變量console.log(count)}returninner// 把內(nèi)層函數(shù)返回出去}constfnouter()// outer()執(zhí)行完后count不會被銷毀fn()// 1fn()// 2fn()// 3三大特性內(nèi)部函數(shù)可以訪問外部函數(shù)作用域的變量外部函數(shù)執(zhí)行完后它的作用域不會被垃圾回收因為閉包函數(shù)持有引用每個閉包都是獨立的作用域用法數(shù)據(jù)私有化functioncreateCounter(){letcount0return{increment:()count,get:()count}}constcountercreateCounter()counter.increment()console.log(counter.get())// 1函數(shù)工廠functionadd(base){returnfunction(b){returnfunction(c){returnbasebc}}}constadd5add(5)constadd56add5(6)constresultadd56(7)console.log(result)// 18防抖節(jié)流防抖每次輸入都充值計時器延遲后才執(zhí)行1次節(jié)流每個時間段只執(zhí)行1次// 防抖停止操作 n ms 后才執(zhí)行functiondebounce(fn,delay300){lettimernull;// ← 閉包變量多次調(diào)用共享returnfunction(...args){clearTimeout(timer);// 每次進(jìn)來清掉上一個timersetTimeout((){fn.apply(this,args);},delay);};}// 節(jié)流每 n ms 最多執(zhí)行一次functionthrottle(fn,interval300){letlastTime0;// ← 閉包變量記錄上次執(zhí)行時間returnfunction(...args){constnowDate.now();if(now-lastTimeinterval){lastTimenow;fn.apply(this,args);}};}內(nèi)存泄露問題場景一長期緩存functionbigData(){consthugenewArray(1000000).fill(data);// 大數(shù)組returnfunction(){console.log(huge.length);}}window.fnbigData();// fn掛在全局永遠(yuǎn)不會釋放huge一直占內(nèi)存原因fn掛在全局永遠(yuǎn)不會釋放huge一直占內(nèi)存。解決window.fnnull;場景二未解綁DOM事件監(jiān)聽functioncreateElement(){constelementdocument.getElementById(button);constlargeData{name:Tom,age:18};element.addEventListener(click,(){console.log(largeData);});returnelement;}原因element 引用了事件監(jiān)聽器函數(shù)的引用事件監(jiān)聽器引用了 largeData 變量導(dǎo)致內(nèi)存泄露。解決一functioncreateElement(){constelementdocument.getElementById(button);constlargeData{name:Tom,age:18};consthandleClick(){console.log(largeData);};element.addEventListener(click,handleClick);return{element,destroy:function(){element.removeEventListener(click,handleClick);}};}constcomponentcreateElement();component.destroy();// 取消事件document.body.removeChild(component.element);// 移除dom元素component.elementnull;// 斷開引用解決二constdataMapnewWeakMap();functioncreateElement(){constelementdocument.getElementById(button);constlargeData{name:Tom,age:18};dataMap.set(element,largeData);element.addEventListener(click,(){console.log(dataMap.get(element));});returnelement;}letelementcreateElement();document.body.removeChild(element);elementnull;// WeakMap會自動清理場景三未清理定時器lettimernull;functionsetup(){consthugeDataloadHugeData();timersetInterval(()console.log(hugeData.length),1000);}functiondestroy(){clearInterval(timer);timernull;}