jstips 實戰:在 JavaScript 陣列中插入元素,push、unshift、splice 與 concat 的效能對比指南 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本篇為 jstips 開源專案的第一篇技巧Tip 00主題是「在既有陣列中插入新元素」的各種寫法與效能實測。讀完後你將掌握在陣列末端push索引賦值concat、起始位置unshiftconcat與中間位置splice插入元素的多種方案並獲得涵蓋行動裝置與桌面瀏覽器的實測基準數據進而在真實專案中做出兼顧可讀性與效能的正確選擇。jstips 專案與本篇 Tip 的定位jstips 是一個收錄「短而實用 JavaScript 技巧」的開源倉庫其 README.md 明確說明每一則 Tip 都能在兩分鐘內讀完主題涵蓋效能、慣例、hack、面試題與這門語言未來的演進方向。本文對應的原文為 在陣列中加入元素正體中文版英文版位於 _posts/en/javascript/2015-12-29-insert-item-inside-an-array.md兩者內容一致。在 README.md 的 Tip 清單中本技巧編號為00排在第一位可見其基礎地位「在既有陣列中插入元素」是每天都會遇到的日常任務。依照倉庫的 POST_TEMPLATE.md 格式每篇 Tip 都帶有title、tip-number、tip-username與categories等 front matter 欄位本篇的tip-number: 00正是系列起點。陣列插入看似簡單但原 Tip 開宗明義地指出「那些都是已知的方法但這並不代表沒有更好的效能的方法。」接下來我們就逐一拆解三種插入位置的完整方案與實測數據。在陣列末端加入新元素三種寫法一次看懂在陣列最後加入元素最直覺的方式是push()但它並非唯一解。原 Tip 給出三種寫法var arr [1, 2, 3, 4, 5]; var arr2 []; arr.push(6); arr[arr.length] 6; arr2 arr.concat([6]);三者的行為差異值得留意arr.push(6)修改原始陣列在末端加入元素並回傳新的length。arr[arr.length] 6同樣修改原始陣列。因為陣列的length永遠比最大索引大 1所以arr[arr.length]天然指向「末端之後的第一個空位」等價於在末端新增。arr.concat([6])不修改原始陣列而是回傳一個包含原陣列所有元素與新元素的新陣列。原 Tip 特別強調「前兩種方法push與索引賦值會修改原始的陣列」而concat屬於不可變immutable操作——這與倉庫中另一篇 將陣列清空的兩種方法 所討論的「參考與原地修改」議題一脈相承若其他變數仍持有原陣列參考使用原地修改方法時這些參考看到的陣列內容也會同步改變。行動裝置上的效能表現原 Tip 作者將三種寫法交由 jsperf 基準測試驗證以下是行動裝置2016 年左右的測試環境的實測數據Androidv4.2.2排名寫法表現1arr.push(6);與arr[arr.length] 6;兩者效能相同3,319,694 ops/sec3arr2 arr.concat([6]);比前兩種方法慢 50.61%Chrome Mobilev33.0.0排名寫法表現1arr[arr.length] 6;6,125,975 ops/sec2arr.push(6);慢 66.74%3arr2 arr.concat([6]);慢 87.63%Safari Mobilev9排名寫法表現1arr[arr.length] 6;7,452,898 ops/sec2arr.push(6);慢 40.19%3arr2 arr.concat([6]);慢 49.78%行動裝置平均勝者arr[arr.length] 6;平均 5,632,856 ops/secarr.push(6);慢 35.64%arr2 arr.concat([6]);慢 62.67%。桌面瀏覽器上的效能表現Chromev48.0.2564排名寫法表現1arr[arr.length] 6;21,602,722 ops/sec2arr.push(6);慢 61.94%3arr2 arr.concat([6]);慢 87.45%Firefoxv44排名寫法表現1arr.push(6);56,032,805 ops/sec2arr[arr.length] 6;慢 0.52%3arr2 arr.concat([6]);慢 87.36%IEv11排名寫法表現1arr[arr.length] 6;67,197,046 ops/sec2arr.push(6);慢 39.61%3arr2 arr.concat([6]);慢 93.41%Operav35.0.2066.68排名寫法表現1arr[arr.length] 6;30,775,071 ops/sec2arr.push(6);慢 71.60%3arr2 arr.concat([6]);慢 83.70%Safariv9.0.3排名寫法表現1arr.push(6);42,670,978 ops/sec2arr[arr.length] 6;慢 0.80%3arr2 arr.concat([6]);慢 76.07%桌面平均勝者arr[arr.length] 6;平均 42,345,449 ops/secarr.push(6);慢 34.66%arr2 arr.concat([6]);慢 85.79%。從上述數據可以歸納出兩個明確結論concat在絕大多數引擎上都是最慢的——因為它需要配置新陣列並複製全部既有元素代價最高兩組平均數據慢 62.67%85.79%都證實了這一點。push與arr[arr.length]的勝負依引擎而定在 Chrome、IE、Opera 與 Chrome Mobile 上索引賦值勝出在 Firefox 與 Safari 上push則以極小差距領先僅慢 0.52%0.80%。可以推斷索引賦值少了方法呼叫的封裝開銷而push在某些引擎中已被深度優化兩者在現代引擎中的差距只會更小。在陣列起始位置加入新元素unshift 與 concat 的對決接著嘗試在陣列開頭插入元素原 Tip 給出兩種寫法var arr [1, 2, 3, 4, 5]; arr.unshift(0); [0].concat(arr);這裡的細節差異與末端插入如出一轍arr.unshift(0)修改原始陣列把全部既有元素向後移一位後在開頭放入新元素。[0].concat(arr)回傳一個新陣列原始arr保持不變。行動裝置上的效能表現Androidv4.2.2排名寫法表現1[0].concat(arr);1,808,717 ops/sec2arr.unshift(0);慢 97.85%Chrome Mobilev33.0.0排名寫法表現1[0].concat(arr);1,269,498 ops/sec2arr.unshift(0);慢 99.86%Safari Mobilev9排名寫法表現1arr.unshift(0);3,250,184 ops/sec2[0].concat(arr);慢 33.67%行動裝置平均勝者[0].concat(arr);平均 4,972,622 ops/secarr.unshift(0);慢 64.70%。桌面瀏覽器上的效能表現Chromev48.0.2564排名寫法表現1[0].concat(arr);2,656,685 ops/sec2arr.unshift(0);慢 96.77%Firefoxv44排名寫法表現1[0].concat(arr);8,039,759 ops/sec2arr.unshift(0);慢 99.72%IEv11排名寫法表現1[0].concat(arr);3,604,226 ops/sec2arr.unshift(0);慢 98.31%Operav35.0.2066.68排名寫法表現1[0].concat(arr);4,102,128 ops/sec2arr.unshift(0);慢 97.44%Safariv9.0.3排名寫法表現1arr.unshift(0);12,356,477 ops/sec2[0].concat(arr);慢 15.17%桌面平均勝者[0].concat(arr);平均 6,032,573 ops/secarr.unshift(0);慢 78.65%。與末端插入不同開頭插入的結論相當一致在 ChromeFirefoxIEOpera 等主流桌面引擎與多數行動環境中[0].concat(arr)明顯勝出unshift甚至慢到 96%99%。僅 Safari含 Safari Mobile v9例外其unshift有較好的優化。從演算法角度理解不難unshift需要把陣列中每個既有元素都向後搬移一個位置O(n) 等級的搬移成本而concat直接以既有陣列為藍本建立新陣列。雖然兩者整體都是 O(n)但在當時多數引擎的實作下concat的複製路徑更貼近引擎的快速路徑。在陣列中間加入元素splice 的正確姿勢要在陣列中間插入元素原 Tip 給出的建議非常直接使用splice這是最具效能的方式。var items [one, two, three, four]; items.splice(items.length / 2, 0, hello);執行後items會變成[one, two, hello, three, four]。關鍵在於splice的三個參數startitems.length / 2插入位置的索引。對長度為 4 的陣列而言4 / 2 2即插入在索引 2第三個位置之前對長度為偶數的陣列這正好是「中間」對奇數長度陣列則會落在中間偏後一格你可以依需求自行調整。deleteCount0要刪除的元素數量設為0表示純插入、不刪除任何既有元素。itemhello要插入的新元素也可以一次傳入多個元素例如items.splice(items.length / 2, 0, hello, world)它們會依序插入。splice是原地in-place操作直接修改原始陣列這與concat的不可變語義正好相反。若需要保持原陣列不變可以先用展開運算符建立副本再splice——倉庫中的 使用 Array 的三個技巧 與 在 JavaScript 中將多維陣列扁平化 都展示了展開運算符與concat的組合應用可作為延伸閱讀。與倉庫中其他陣列技巧的橫向關聯本 Tip 討論的「插入元素」只是陣列操作的一環。在 jstips 倉庫的_posts/zh_TW/javascript/目錄下還有幾篇與此高度互補的技巧適合一併閱讀將陣列清空的兩種方法list []重新指派參考與list.length 0原地清空的差異與本 Tip 中「原地修改 vs 回傳新陣列」的語義對比互為鏡像。使用 Array 的三個技巧展開運算符在迭代空陣列、傳送空參數與陣列去重上的應用。在 JavaScript 中將多維陣列扁平化[].concat.apply([], myArray)與[].concat(...myArray)都是concat的高階用法正好延伸了本 Tip 對concat的討論。從陣列計算最大和最小值同樣比較「傳統寫法 vs 展開運算符」的兩種陣列應用思路。這些 Tip 共同構成了 jstips 系列中「陣列操作」的完整知識塊讀者可依此脈絡深入倉庫其餘 70 餘篇技巧。如何自行驗證效能原 Tip 作者在結尾強調「我嘗試在不同的瀏覽器和 OS 執行這些測試結果是相似的。我希望這些知識對你是有幫助的也鼓勵你自己進行測試」這正是 jstips 的精神——數據會因引擎版本、硬體與陣列大小而漂移關鍵結論必須由自己驗證。如果你要在現代環境中重跑這組基準測試可以遵循以下通用做法不屬於倉庫內建腳本在瀏覽器中用performance.now()量測大量迭代例如 100 萬次的總耗時再換算為每秒操作數ops/sec在 Node.js 環境中可使用process.hrtime.bigint()或performance.now()取得高精度時間為避免引擎的 JIT 優化造成偏差應交錯執行不同方案、增加迭代次數並以多次取樣的平均值為準注意測試的瀏覽器與 OS 版本並如原 Tip 一樣分開記錄行動裝置與桌面環境。需要再次強調的是原 Tip 的實測數據對應的是 20152016 年左右的引擎Chrome v48、Firefox v44、IE11、Safari v9 等。現代 V8、SpiderMonkey 等引擎對push、unshift都做了大量優化具體數字必然不同但「concat因建立新陣列而開銷較大」「unshift因搬移元素而在多數引擎偏慢」的相對趨勢仍然值得參考。總結回到本 Tip 的三個核心結論末端插入push()與arr[arr.length] 6都是原地操作且效能相近concat則因建立新陣列而普遍最慢平均慢 60%85%。在現代程式碼中push()可讀性最佳是日常推薦寫法追求極致效能且在意舊引擎差異時可考慮索引賦值。開頭插入[0].concat(arr)在多數引擎上遠勝unshift桌面平均慢 78.65%但兩者語義不同——前者回傳新陣列、後者原地修改。若需要保留原陣列concat一舉兩得。中間插入splice(index, 0, item)是最直接的方案參數語義清晰支援一次插入多個元素。最後效能永遠是「依情境而異」的命題。正如本 Tip 開頭所說這些方法都是已知的真正的價值在於理解每一種寫法的語義差異原地 vs 回傳新陣列與量級成本O(1) 末端 vs O(n) 開頭/中間再結合自己專案的實際引擎與數據做出選擇。全文原始出處為 _posts/zh_TW/javascript/2015-12-29-insert-item-inside-an-array.md歡迎直接查閱原文並在本地執行你自己的基準測試。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐jstips 第 00 号技巧向 JavaScript 数组中插入元素的高效之道——push、unshift、splice 的语义与 jsperf 性能实测jstips 第 00 号技巧向 JavaScript 数组中插入元素的高效之道——push、unshift、splice 的语义与 jsperf 性能实测教程jstips 数组插入性能优化push、unshift、splice 的高效替代写法jstips 数组插入性能优化push、unshift、splice 的高效替代写法 向已有数组中插入元素是日常开发中最常见的操作之一本指南基于 jstip教程Hello 演算法圖的基礎操作 — 鄰接矩陣與鄰接表的增刪查改、複雜度分析與實戰對比Hello 演算法圖的基礎操作 — 鄰接矩陣與鄰接表的增刪查改、複雜度分析與實戰對比 本文以《Hello 演算法》hello algo繁體中文版 圖的基礎教程文档示例工程教育上一篇MediaMTX流媒体服务器终极指南解决HLS协议卡顿问题的10个技巧下一篇awesome-deep-text-detection-recognition深度学习方法在文本检测识别领域的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考