跳轉到

2019:ECMAScript 2019——扁平化陣列#

事件#

2019年6月,ECMAScript 2019(ES10) 發佈,主軸是陣列扁平化與「程式碼衛生」類的小改進。

新語法與特性#

1. Array.prototype.flat / flatMap#

  • 為何加入:巢狀陣列扁平化以前要手寫遞迴或用 [].concat.apply([], arr) 駭客寫法(且多層巢狀無法一次攤平)。
  • 理論原因:flatMap 是 map + flatten 的組合,源自函數式語言(Scala、Haskell 的 bind/join 傳統),是單子(monad)操作在大眾語言中的罕見現身。
  • 實用原因:JSON 資料解析(樹狀結構攤平成清單)、多層分組資料的處理。
  • 彌補缺陷:巢狀陣列處理工具缺失與 concat 駭客寫法。

2. Object.fromEntries#

  • 為何加入:ES2017 有 Object.entries(物件→陣列),反方向(陣列→物件)要手寫 reduce。
  • 理論原因:與 entries 對稱,完成「物件↔鍵值對陣列」的雙向轉換迴路。
  • 實用原因:Map↔Object 轉換、查詢字串解析(URLSearchParams → 物件)。
  • 彌補缺陷:物件轉換 API 的不對稱。

3. String.trimStart / trimEnd#

  • 為何加入:ES5 只有 trim()(兩端都修剪),只需修一端時要手寫 regex。
  • 理論原因:借鑑 Python 的 lstrip/rstrip 命名傳統。
  • 彌補缺陷:單端修剪工具缺失。

4. try...catch 可省略 catch 綁定(optional catch binding)#

  • 為何加入:很多時候不需要錯誤物件,卻被迫寫 catch (e)——未使用的變數是語法噪音。
  • 實用原因:try { JSON.parse(s) } catch { return null } 這類「失敗就放棄」模式更簡潔。
  • 彌補缺陷:強制綁定造成未使用變數的語法噪音。

5. 其他#

  • Symbol.prototype.description、Array.prototype.sort 等方法的穩定性要求(stable sort 成為規範)、JSON.stringify 的 Unicode 修正、Function.prototype.toString 精確化。

理論總結#

ES2019 的主軸是「對稱補齊與程式碼衛生」:fromEntries 補齊 entries 的反面、flat 補齊巢狀處理、可省略 catch 綁定消除語法噪音。語言進入「打磨期」——大架構(ES6–ES8)已定,剩餘的是精緻化。

實用總結#

這一年的特性都不改變程式設計範式,但每一項都消除一個常見的駭客寫法(concat.apply、[\s\S]、var self),實際上減少了生態中「樣板與陷阱」的存量。

相關條目#

程式範例#

1. flat / flatMap:巢狀陣列的解法#

// ES2018 之前:concat 駭客寫法(只能攤一層)
[1, [2, 3], [4, [5]]].concat.apply([], [[1], [2]]);  // 複雜且多層無法一次攤平

// ES2019:flat
[1, [2, 3], [4, [5]]].flat();      // [1, 2, 3, 4, [5]]——攤一層
[1, [2, [3, [4]]]].flat(Infinity); // [1, 2, 3, 4]——全攤平

// flatMap:map + flatten(函數式的 monad 操作)
["hello world", "foo bar"].flatMap((s) => s.split(" "));
// ["hello", "world", "foo", "bar"]——map 之後再攤平,一行完成

2. Object.fromEntries:物件↔陣列的雙向迴路#

// ES2017 有 entries,反方向要手寫 reduce
Object.entries({ a: 1, b: 2 });              // [["a",1], ["b",2]]——物件→陣列

// ES2019:fromEntries——陣列→物件
Object.fromEntries([["a", 1], ["b", 2]]);    // { a: 1, b: 2 }

// 實用案例:Map↔Object 轉換、URL 查詢字串解析
const params = new URLSearchParams("?a=1&b=2");
Object.fromEntries(params);                  // { a: "1", b: "2" }

3. 可省略 catch 綁定:消除語法噪音#

// ES2018:不需要錯誤物件也要寫 catch (e)
try { JSON.parse(text) } catch (e) { return null }

// ES2019:直接省略
try { JSON.parse(text) } catch { return null }

4. trimStart / trimEnd#

"  hi  ".trim();       // "hi"(ES5,兩端)
"  hi  ".trimStart();  // "hi  "(只修左端——Python lstrip 對照)
"  hi  ".trimEnd();    // "  hi"