記得嗎?兩週前我(或者說其實是我自己)還答應過你,從那之後我只會寫輕鬆、簡單的文章?嗯……我破戒了 😅 上週我發了一篇超長文章,主題是你能想像得到的最不性感的議題之一:遺留應用程式。沒想到即使如此,DEV 編輯團隊還是很喜歡,甚至把它選進了本週前 7 篇文章 ❤️

但今天總算輪到一個輕鬆一點的主題了。我覺得這個主題其實很值得多一點關注。

這些日子我們花很多時間在談 AI 代理人,我完全理解原因,因為這確實是個很迷人的領域。但我有時候會覺得,我們忘了自己每天使用的程式語言也在進化。

我大多數時間都在寫 JavaScript(好吧……當然是 TypeScript 😄)。沒錯,這幾年整個生態系已經成熟很多了。我們不再有沒完沒了的 React 對 Angular 大戰。也大致告別了那種每個人一個月前還愛死 Redux,六個月後又覺得它是個過度設計的怪物,然後把它從每個應用程式裡刪掉的年代 😅。

但生態系和 ECMAScript 標準都還在持續演進。

在 2015 年傳奇性的 ES6 發布之後,它徹底改變了前端開發,TC39 委員會改採迭代式的做法,開始每年推出新功能。

而好訊息是,如果你使用的是現代瀏覽器或執行環境,通常幾乎可以立刻用到這些功能。

那麼,在 ECMAScript 2026 裡我們得到了什麼?

對了,為了讓內容更有趣,本文中的所有程式碼範例,都是基於虛構的 LinkedIn 大師們充滿強烈觀點的內心獨白。若與現實中的任何人物有相似之處,當然純屬巧合 😇

本系列的其他文章:


1. Map.prototype.getOrInsert() / Upsert

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/getOrInsert

這是那種會讓你忍不住想問:「等等……我們十年前為什麼沒有這個?」的功能之一。

想像我們正在收集 LinkedIn 大師們的觀點。到目前為止,我們得像這樣做:

const opinions = new Map();

function addOpinion(topic, author) {
  if (!opinions.has(topic)) {
    opinions.set(topic, []);
  }

  opinions.get(topic).push(author);
}

addOpinion("React is dead", "10x Engineer");
addOpinion("React is dead", "Principal AI Evangelist");

這樣是可以運作,但樣板程式碼不少。

有了 ES2026,事情就優雅多了:

const opinions = new Map();

opinions
  .getOrInsert("React is dead", [])
  .push("10x Engineer");

opinions
  .getOrInsert("React is dead", [])
  .push("Principal AI Evangelist");

console.log(opinions);

我們還有一個計算版本:

const opinions = new Map();

opinions
  .getOrInsertComputed(
    "沒有人再寫乾淨的程式碼了",
    () => []
  )
  .push("DDD 教條派");

說真的,這樣乾淨又好讀多了。拿來做快取也超適合!程式碼更少,API 也更漂亮。


2. Iterator.concat()

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/concat

在談 concat() 之前,我們先快速回答一個問題:

什麼是 iterator(迭代器)?

Iterator 基本上就是一個游標,讓我們可以一次消耗一個元素的資料,而不需要把全部內容都存進記憶體。

例如:

const posts = [
  "Angular is dead",
  "JavaScript was a mistake"
];

const iterator = posts.values();

console.log(iterator.next());
// { value: "Angular is dead", done: false }

console.log(iterator.next());
// { value: "JavaScript was a mistake", done: false }

console.log(iterator.next());
// { value: undefined, done: true }

而且因為 iterator 是延遲求值的,我們甚至可以產生無限序列而不會把記憶體炸掉:

function* endlessHotTakes() {
  while (true) {
    yield "Everything should be rewritten in Rust.";
  }
}

const iterator = endlessHotTakes();

console.log(iterator.next().value);
console.log(iterator.next().value);
console.log(iterator.next().value);

去年我們得到了 Iterator Helpers,新增了像 map()filter() 之類的功能:

function* linkedinFeed() {
  yield "Use Rust for everything";
  yield "JavaScript was a mistake";
  yield "Clean code is dead";
  yield "Angular is dead";
}

const controversialTakes =
  linkedinFeed()
    .filter(post => post.includes("dead"))
    .map(post => `🔥 ${post}`);

console.log([...controversialTakes]);

現在又多了一個很棒的補充:Iterator.concat()。假設前端大師和後端大師各自有自己的智慧串流:

function* frontendExperts() {
  yield "React is dead";
  yield "Nobody needs Redux";
}

function* backendExperts() {
  yield "Microservices solve everything";
  yield "Frontend developers don't understand architecture";
}

現在我們可以優雅地把它們合併:

const feed = Iterator.concat(
  frontendExperts(),
  backendExperts()
);

console.log([...feed]);

我認為,這些 iterator 相關功能得到的關注,遠遠少於它們應得的程度。


3. Array.fromAsync()

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fromAsync

這基本上就是我們喜愛的 Array.from() 的非同步版本。

它主要是為非同步 iterator 設計的,不過我猜很多 JavaScript 開發者平常不會天天用到非同步 iterator。舉例來說,想像 LinkedIn 的留言一則一則湧入:

async function* angryComments() {
  yield "這本來可以只是一個普通的 HTML 表單。";
  yield "Angular is dead.";
  yield "React is dead.";
  yield "JavaScript was a mistake.";
}

const comments = await Array.fromAsync(
  angryComments()
);

console.log(comments); 
// 這本來可以只是一個普通的 HTML 表單。
// Angular is dead.
// 等等

但很多人沒有意識到的是:它也能搭配 promise 使用。

const opinions = [
  Promise.resolve("沒有人應該使用類別。"),
  Promise.resolve("Signals 改變了一切。"),
  Promise.resolve("Microservices 毀了軟體。")
];

const takes = await Array.fromAsync(opinions);

console.log(takes); 

而且你甚至可以立刻對值做映射:

const comments = await Array.fromAsync(
  angryComments(),
  opinion => opinion.toUpperCase()
);

console.log(comments);

相當方便。


4. Math.sumPrecise()

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sumPrecise

這個功能解決的是一個幾乎跟網際網路一樣古老的浮點數問題 😄 如大家所知,在 JavaScript 中:

console.log(0.1 + 0.2);
// 0.30000000000000004

今天我就不深入解釋為什麼會這樣:不然我們今晚都不用睡了 😄

重點是,ES2026 引入了 Math.sumPrecise(),它可以做更精確的加總,避免四捨五入誤差的累積。

假設某位 LinkedIn 大師列出所有據稱能提升生產力的事:

const productivityBoosts = [
  0.1, // 冷水澡
  0.2, // AI 代理人
  0.3, // 寫日誌
  0.4, // 凌晨 4 點起床
];

console.log(
  Math.sumPrecise(productivityBoosts)
);

公平地說,大多數前端開發者大概永遠不需要這個。單純的加法在日常使用上其實完全沒問題。

但如果你在做金融、統計、模擬,或 AI/ML 相關工作,微小誤差會在成千上萬甚至百萬次運算中累積,這就會變得有趣得多。


5. Error.isError()

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/isError

這個功能大概比較偏向函式庫作者和進階開發者。或者不一定?😉 到目前為止,確認某個東西是不是實際的 error,通常像這樣:

try {
  throw new Error(
    "Angular is dead."
  );
}
catch (e) {

  console.log(
    e instanceof Error
  );
}

大多數時候,這完全沒問題。直到它出問題為止。

如果某個 error 來自另一個 realm,例如 iframe、Web Worker 或 VM context,instanceof Error 可能會突然背叛你:

const strangeThing =
  window.frames[0].eval(
    "new Error('JavaScript was a mistake.')"
  );

console.log(
  strangeThing instanceof Error
);

// false 

這個問題多年來一直讓函式庫作者很頭痛,所以很多框架和函式庫都自己寫了檢查 error 的輔助函式。現在我們終於有內建解法了:

console.log(
  Error.isError(strangeThing)
);

// true

簡單又漂亮。


6. Uint8Array 的 Base64

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toBase64

快速提醒一下:Base64 就是一種把二進位資料轉成純文字的方式。為什麼要這麼做?因為許多通訊協定和格式,比起原始位元組,更喜歡處理文字。例如,我們可以把圖片當成 Base64 字串傳送。

現在有人可能會說:「等等,JavaScript 早就有 Base64 了啊!」沒錯,確實有。但它主要是跟字串一起用:

btoa("JavaScript was a mistake.");

但處理二進位資料時,事情很快就變得很醜:

const bytes = new Uint8Array(buffer);

const base64 = btoa(
  String.fromCharCode(...bytes)
);

不算太糟,但絕對稱不上優雅。

現在我們只要這樣寫:

const screenshot =
  await fetch(
    "/proof/react-is-dead.png"
  );

const bytes =
  new Uint8Array(
    await screenshot.arrayBuffer()
  );

const base64 =
  bytes.toBase64();

console.log(base64);

乾淨多了。也許更重要的是,六個月後會更容易看懂。


7. JSON.parse 原始文字存取

MDN:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

JSON.parse() 很棒。直到有人傳給你一個超大的數字。假設某位 LinkedIn 大師宣稱自己有 999 兆粉絲:

const json = `
{
  "followers":
  999999999999999999999999999999
}
`;

const data = JSON.parse(json);

console.log(data.followers);

糟了。JavaScript 的數字有上限,超大的整數可能會失去精度。

有了 ES2026,reviver 回呼可以存取原始來源文字,讓我們能安全地還原超大數值:

const data = JSON.parse(
  json,
  (key, value, context) => {

    if (key === "followers") {
      return BigInt(context.source);
    }

    return value;
  }
);

console.log(data.followers);

不會再不小心把超大數字弄壞了。

我們大多數人不會每天都需要這個。但如果你在處理 ID、財務資料,或巨大的整數值,這可以幫你避免一些很惱人的 bug。


加碼:那些缺席的大功能

我原本真的很希望這些功能能進 ES2026,但很可惜我們還得再等一年。

呃,算是吧。現代瀏覽器和執行環境其實已經開始實作它們了,但它們還不是 ECMAScript 2026 規格的正式一部分。

這大概是我個人最期待的兩個功能。


Temporal API

TC39 提案:
https://github.com/tc39/proposal-temporal

如果你做前端開發夠久,八成至少曾經有過一次跟日期有關的創傷經驗。可能像這樣:

const date = new Date("2026-03-30");

console.log(date);

根據你的時區,恭喜!你剛進入了這個令人興奮的世界:「為什麼現在是昨天?」

或者你可能體驗過大家最愛的這個:

const today = new Date();

today.setMonth(today.getMonth() + 1);

然後你突然開始除錯,為什麼三月加一個月竟然變成了五月。

或者你可能很幸運地碰過時區問題。

這時你會發現,時間本身似乎只是幻覺,而日光節約時間就是專門為了摧毀程式設計師人生而發明的。

這也是為什麼很多人最後都改用像 Moment.js 這類函式庫。有趣的是,就連 Moment.js 維護者現在也建議使用其他方案。後來又出現了 date-fns、Luxon,以及其他各種試圖恢復理智的工具。

它們當然有幫助。直到有人說:「對了,澳洲的使用者回報怪 bug。」通常那就是好戲開始的地方。

Temporal 的目標就是透過引入正確的日期與時間型別來解決這一切。

不是:

const now = new Date();

而是像這樣:

const now = Temporal.Now.instant();

const birthday =
  Temporal.PlainDate.from(
    "1987-07-23"
  );

const meeting =
  Temporal.ZonedDateTime.from(
    "2026-11-03T10:00:00[Europe/Warsaw]"
  );

然後一切都突然變得更明確了。

順帶一提,我花了非常丟臉的時間,才搞清楚 Temporal 到底有沒有真的進入 ES2026。最後我找到 TC39 的儲存庫,上面清楚寫著:雖然這個提案已經到達 Stage 4,但預計發佈年份是 2027。

所以我們已經很接近了。非常接近。我等不及了 ❤️


明確資源管理(using

TC39 提案:
https://github.com/tc39/proposal-explicit-resource-management

這是那種 C# 和 Python 開發者早就默默享受,而我們其他人卻假裝 try/finally 已經夠好的功能 😄

有時候你會建立一個之後需要清理的東西:檔案、資料庫連線、串流、WebSocket 等等。今天我們通常會這樣寫:

const webinar =
  createAIAgentsWebinar();

try {

  webinar.start();

}
finally {

  webinar.close();

}

finally 區塊常常寫得像是在寫單元測試一樣不情不願。更糟的是,如果我們完全忘了它,可能會導致資源洩漏和神祕 bug。

有了 using,當離開作用域時就會自動清理:

using webinar =
  createAIAgentsWebinar();

webinar.start();

一旦離開作用域,JavaScript 就會自動呼叫清理邏輯。是不是很酷?

這種功能可能不會每天影響一般前端開發者,但對 Node.js 開發者、函式庫作者,以及處理串流和檔案的人來說,會非常有用。


唉……

我得承認,這篇文章最後比我原本預期的還要費工得多 😅 本來應該只是短短輕鬆的一篇。結果我居然一路挖到了 TC39 提案、MDN 頁面、瀏覽器實作,還在努力確認 Temporal 到底有沒有進 ES2026。

不過我希望這些努力是值得的,也希望你喜歡這篇文章 ❤️

那你呢?哪個功能最讓你驚訝?而且你是不是也正熱切等待 Temporal 終於把我們從所有跟日期有關的痛苦中解放出來?

(或者至少這大概就是 LinkedIn 大師們下週會告訴我們的事 😇)


如果你喜歡這篇文章,歡迎到我的 LinkedIn 加我😊


原文出處:https://dev.to/sylwia-lask/7-new-javascript-features-and-2-im-still-waiting-for-2ck8


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝13   💬2   ❤️1
731
🥈
我愛JS
📝1   ❤️1
67
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登