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 是語法錯誤,要靠載入器繞過