組的兩種方式,從引用語義到內(nèi)存泄漏)
教程【免費(fèi)下載鏈接】jstipsThis is about useful JS tips!項(xiàng)目地址https://gitcode.com/gh_mirrors/js/jstips點(diǎn)擊查看免費(fèi)下載本篇文章基于 JS Tips 開源倉庫中的_posts/es_ES/javascript/2016-01-22-two-ways-to-empty-an-array.md及其多語言版本英文版、簡(jiǎn)體中文版、繁體中文版展開。當(dāng)你在業(yè)務(wù)代碼中需要清空一個(gè)數(shù)組時(shí)最常見的方式是重新賦值list []但這實(shí)際上只是把變量指向了一個(gè)新數(shù)組。本文要解決的核心問題是如何真正清空數(shù)組的底層內(nèi)容、避免無謂的內(nèi)存占用并理解兩種寫法對(duì)共享同一數(shù)組的其他引用產(chǎn)生的截然不同的影響。讀完本文你將掌握list.length 0與list []的本質(zhì)區(qū)別能在內(nèi)存敏感或存在多引用的場(chǎng)景中做出正確選擇并能準(zhǔn)確預(yù)測(cè)含別名引用的數(shù)組清空代碼的輸出結(jié)果。兩種清空數(shù)組的寫法假設(shè)你定義了一個(gè)數(shù)組現(xiàn)在想清空它的內(nèi)容。常規(guī)寫法是重新賦值為一個(gè)新數(shù)組// 定義一個(gè)數(shù)組 var list [1, 2, 3, 4]; function empty() { // 清空數(shù)組 list []; } empty();但原文檔指出還有一種效率更高的清空數(shù)組的方式——直接修改數(shù)組自身的length屬性var list [1, 2, 3, 4]; function empty() { // 清空數(shù)組 list.length 0; } empty();兩種寫法執(zhí)行后list的值都是[]但它們?cè)诘讓幼龅氖虑橥耆煌罄m(xù)產(chǎn)生的副作用也天差地別。本質(zhì)區(qū)別換引用 vs 刪內(nèi)容這是本篇技巧的核心。原文檔對(duì)兩種方式給出了精煉的定性list []是換引用它把一個(gè)新的數(shù)組對(duì)象的引用賦值給變量list而其他任何指向舊數(shù)組的引用不受影響。舊數(shù)組的內(nèi)容只要還被其他引用持有就會(huì)繼續(xù)留在內(nèi)存中這可能導(dǎo)致內(nèi)存泄漏。list.length 0是刪內(nèi)容它把數(shù)組的length置為 0從而刪除數(shù)組里的所有元素同時(shí)會(huì)影響到其他引用——所有指向這個(gè)數(shù)組的變量看到的都是同一個(gè)空數(shù)組。換句話說如果你有兩個(gè)變量引用同一個(gè)數(shù)組a [1,2,3]; a2 a;使用list.length 0清空內(nèi)容后a和a2這兩個(gè)引用現(xiàn)在都指向同一個(gè)空數(shù)組。原文檔特意提醒如果你不希望a2變成空數(shù)組就不要使用這種技術(shù)。這一行為與倉庫中另一篇技巧 Know the passing mechanism第 44 期闡述的引用語義完全一致JavaScript 中對(duì)象數(shù)組也屬于對(duì)象的引用值是按值傳遞的多個(gè)變量可以持有對(duì)同一底層對(duì)象的引用對(duì)對(duì)象內(nèi)部狀態(tài)的修改會(huì)透過所有引用被看到而對(duì)變量本身重新賦值則只影響該變量。list []屬于改變變量指向list.length 0屬于修改對(duì)象內(nèi)部狀態(tài)兩者在引用模型中的層級(jí)完全不同。思考這段代碼的輸出原文檔給出了一個(gè)經(jīng)典的驗(yàn)證片段請(qǐng)先自己想一想輸出是什么再看答案var foo [1,2,3]; var bar [1,2,3]; var foo2 foo; var bar2 bar; foo []; bar.length 0; console.log(foo, bar, foo2, bar2); // [] [] [1, 2, 3] []逐行推演foo和bar各自創(chuàng)建了一個(gè)獨(dú)立的新數(shù)組[1, 2, 3]foo2 foo讓foo2與foo指向同一個(gè)數(shù)組對(duì)象bar2 bar同理foo []只是讓foo指向一個(gè)全新的空數(shù)組不觸碰原數(shù)組內(nèi)容因此foo2仍然持有完整的[1, 2, 3]bar.length 0直接清空了bar與bar2共同指向的那個(gè)數(shù)組所以bar和bar2都變成[]。最終輸出[] [] [1, 2, 3] []foo和bar都是空數(shù)組但foo2保留原數(shù)據(jù)因?yàn)閒oo只是換了引用bar2被連帶清空因?yàn)閎ar刪除了共享數(shù)組的內(nèi)容。這個(gè)例子把兩種方式的差異表現(xiàn)得淋漓盡致。深入理解length 屬性與內(nèi)存釋放length是數(shù)組對(duì)象的一個(gè)可寫屬性把它設(shè)置為0會(huì)觸發(fā)數(shù)組元素的批量移除被移除的元素不再被數(shù)組引用因而在無其他引用的情況下可以被垃圾回收器回收。這正是list.length 0相較于重新賦值更受青睞的原因——它不產(chǎn)生舊數(shù)組內(nèi)容仍被引用、滯留在內(nèi)存中的問題。從源碼結(jié)構(gòu)看本倉庫并未包含可運(yùn)行的 JavaScript 實(shí)現(xiàn)或測(cè)試代碼倉庫以 Markdown 技巧文檔為主見 README.md 的 Tips 列表因此上述內(nèi)存回收結(jié)論屬于 ECMAScript 規(guī)范層面的語言行為。需要說明的是原文檔斷言list.length 0更高效more performant這一結(jié)論本身沒有附帶基準(zhǔn)數(shù)據(jù)我們可以把它理解為在需要清空并且該數(shù)組對(duì)象仍被多處引用時(shí)直接修改length避免了額外分配一個(gè)新數(shù)組對(duì)象的開銷同時(shí)確保了所有引用方的一致性。若以嚴(yán)謹(jǐn)?shù)墓こ虘B(tài)度對(duì)待建議在具體場(chǎng)景下用 性能測(cè)量技巧第 13 期提供的方法自行驗(yàn)證。其他常見的清空手段與適用場(chǎng)景除了上述兩種方式日常代碼中還有一些替代寫法它們各自有明確的適用邊界寫法行為是否影響其他引用典型場(chǎng)景l(fā)ist []變量指向新數(shù)組舊數(shù)組留給其他引用否只想讓當(dāng)前變量丟棄這批數(shù)據(jù)list.length 0原地刪除全部元素是所有引用同時(shí)變空想真正釋放/復(fù)用當(dāng)前數(shù)組對(duì)象list.splice(0, list.length)原地刪除全部元素返回被刪元素是需要拿到被刪除元素的場(chǎng)景while (list.pop())或循環(huán)shift()逐個(gè)彈空原地刪除是需要逐元素處理、副作用明顯的場(chǎng)景性能較低值得提醒的是Array.prototype上還有大量與內(nèi)容變換相關(guān)的方法Looping over arrays 第 79 期、3 Array Hacks 第 64 期對(duì)此有系統(tǒng)梳理但它們普遍是返回新數(shù)組而非原地清空使用時(shí)要注意區(qū)分。實(shí)戰(zhàn)建議什么時(shí)候選哪一種綜合原文檔的結(jié)論與引用語義可以沉淀出以下選擇準(zhǔn)則當(dāng)數(shù)組對(duì)象被多個(gè)變量/屬性共享且你希望所有引用方都同時(shí)變空比如組件內(nèi)部維護(hù)的一個(gè)列表被渲染邏輯和業(yè)務(wù)邏輯共同持有優(yōu)先用list.length 0當(dāng)你不希望其他引用受影響比如只想讓當(dāng)前變量換一批數(shù)據(jù)舊的交給別人或者數(shù)組會(huì)被徹底丟棄、隨后整體重建用list []更合適在內(nèi)存敏感的長(zhǎng)生命周期應(yīng)用中如果舊數(shù)組內(nèi)容仍被其他引用持有重新賦值不會(huì)釋放內(nèi)存此時(shí)評(píng)估是否改用原地清空以幫助 GC 回收函數(shù)參數(shù)傳數(shù)組時(shí)尤其要小心結(jié)合 Know the passing mechanism 的結(jié)論在函數(shù)內(nèi)對(duì)參數(shù)執(zhí)行arr.length 0會(huì)透?jìng)鞯秸{(diào)用方可能引發(fā)意想不到的副作用若只想在局部清空應(yīng)顯式創(chuàng)建新數(shù)組或先拷貝拷貝本身也有深淺之分見 Immutable structures and cloning 第 78 期。小結(jié)清空數(shù)組的兩種方式在結(jié)果上都是數(shù)組變空但語義完全不同list []只是更換了變量的引用舊數(shù)組內(nèi)容可能繼續(xù)駐留內(nèi)存并產(chǎn)生內(nèi)存泄漏風(fēng)險(xiǎn)list.length 0則是原地刪除全部元素會(huì)影響所有共享該數(shù)組的引用。本文的驗(yàn)證片段[] [] [1, 2, 3] []正是對(duì)這一差異的直觀證明。下次清空數(shù)組時(shí)請(qǐng)先問自己一句這個(gè)數(shù)組對(duì)象還有別人在引用它嗎答案將決定你選擇哪一種寫法。贊分享教程【免費(fèi)下載鏈接】jstipsThis is about useful JS tips!項(xiàng)目地址https://gitcode.com/gh_mirrors/js/jstips點(diǎn)擊查看免費(fèi)下載相關(guān)推薦jstips 第 22 期清空 JavaScript 數(shù)組的兩種方式——list [] 與 list.length 0 的引用語義、內(nèi)存影響與選型指南jstips 第 22 期清空 JavaScript 數(shù)組的兩種方式——list 與 list.length 0 的引用語義、內(nèi)存影響與選型指南 本文教程jstips 第 38 期JavaScript 多維數(shù)組扁平化的五種實(shí)用方案jstips 第 38 期JavaScript 多維數(shù)組扁平化的五種實(shí)用方案 導(dǎo)讀 本文基于 jstips 倉庫第 38 號(hào)技巧 西班牙語原文 https:教程PaddleOCR EAST 文本檢測(cè)算法全解析從論文原理到訓(xùn)練推理部署實(shí)戰(zhàn)PaddleOCR EAST 文本檢測(cè)算法全解析從論文原理到訓(xùn)練推理部署實(shí)戰(zhàn) 導(dǎo)讀 EASTEfficient and Accurate Scene Tex教程上一篇魔獸爭(zhēng)霸3輔助WarcraftHelper地圖大小解鎖、寬屏適配與FPS解鎖完整設(shè)置指南下一篇免費(fèi)開源 Forza Mods AIO地平線4/5修改完整指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考