跳轉到

2023:ECMAScript 2023——不可變陣列方法#

事件#

2023年6月,ECMAScript 2023(ES14) 發佈,主軸是不可變(by-copy)陣列方法——不改動原陣列、回傳新陣列的排序/反轉/修改方法。

新語法與特性#

1. toSorted / toReversed / toSpliced / with#

  • 為何加入:sort()、reverse()、splice() 都原地修改(mutate)原陣列——這是著名陷阱:React/Redux 等不可變資料範式中,原地修改會導致狀態被偷改、UI 不更新。以前要寫 [...arr].sort()(先複製再排序)。
  • 理論原因:對應不可變資料結構(persistent data structure)的正統操作——「回傳新值、不動舊值」;命名採 toXxx 慣例(類似 toString)。
  • 實用原因:React 狀態更新、函數式風格程式碼要求純函數(無副作用)——原地修改的 sort 是最常見的副作用 bug 來源。
  • 彌補缺陷:陣列方法「原地修改」的歷史設計缺陷,以及「先複製再操作」的樣板。

2. findLast / findLastIndex#

  • 為何加入:從尾端找元素以前要 [...arr].reverse().find(...) 或手寫倒序迴圈(reverse 還會原地修改!)。
  • 實用原因:日誌找最後一筆、清單找最後符合項是常見操作;一次遍歷即可,比先反轉更高效。
  • 彌補缺陷:搜尋方向的不對稱(只有 find 沒有 findLast)。

3. Hashbang(#!)語法#

  • 為何加入:CLI 腳本(Node 程式)的第一行 shebang(#!/usr/bin/env node)以前會造成語法錯誤,要靠載入器特殊處理。
  • 理論原因:對齊 Unix 可執行腳本傳統(Python、Ruby 都原生支援 shebang)。
  • 實用原因:chmod +x script.mjs 直接執行,CLI 工具開發更順暢。
  • 彌補缺陷:Unix 執行腳本與 JS 語法的不相容。

理論總結#

ES2023 的主軸是「不可變性成為語言一等公民」:2013年 React 開始倡導不可變資料、2018年物件展開運算子落地,2023年陣列方法終於原生支援 by-copy 操作。語言追上了生態的範式轉移——這是「框架先行、語言後收」的另一案例。

實用總結#

toSorted/with 消滅了 [...arr].sort() 這類樣板,也消滅了「忘了複製就 sort」的副作用 bug 類別。

相關條目#

程式範例#

1. 原地修改的陷阱:React 狀態被偷改#

// 著名陷阱:sort()、reverse()、splice() 都是原地修改
const state = [3, 1, 2];
const sorted = state.sort();    // sorted = [1,2,3],但 state 也變 [1,2,3]!
// React:同一個引用 → 認為狀態沒變 → UI 不更新

// 以前的解方:先複製再排序(樣板)
const sorted = [...state].sort();

// ES2023:toXxx 系列——回傳新陣列,不動原陣列
const sorted = state.toSorted();      // state 保持 [3,1,2],sorted = [1,2,3]
const reversed = state.toReversed();
const spliced = state.toSpliced(0, 1);        // 對照 splice() 的不可變版
const replaced = state.with(1, 99);           // [3, 99, 2]——指定索引替換,回傳新陣列

2. findLast / findLastIndex:從尾端搜尋#

const logs = [
  { level: "warn",  msg: "disk" },
  { level: "error", msg: "db" },
  { level: "error", msg: "api" }
];

// ES2022 之前:從尾端找要反轉(還會原地修改!)或手寫倒序迴圈
const lastError = [...logs].reverse().find((l) => l.level === "error");

// ES2023:一次遍歷、不修改、可讀
const lastError = logs.findLast((l) => l.level === "error");        // { level:"error", msg:"api" }
const lastIdx = logs.findLastIndex((l) => l.level === "error");     // 2

3. Hashbang:Unix 可執行腳本#

#!/usr/bin/env node        // ES2023:語言原生支援 shebang
// script.mjs
console.log("CLI 工具");
chmod +x script.mjs
./script.mjs               # 直接執行——以前 shebang 是語法錯誤,要靠載入器繞過