TC39JavaScript新語法Pipeline Operator函式編程

TC39 新語法深度解析(九):Pipeline Operator — 用 |> 寫出更易讀的資料轉換鏈

整理 TC39 Pipeline Operator(Stage 2)的 Hack pipe 語法(|>)。與 F#/Elixir pipe 的比較,以及與 Iterator Helpers 結合的 streaming transform 實例。

· 2 分鐘閱讀

這是 TC39 新語法深度解析系列的第九篇。Pipeline Operator 是 TC39 歷史上最具爭議的提案之一——經過了十年的討論和一個重大分歧(Hack pipe vs F# pipe)才終於接近標準化。⚠️ 本文內容基於 Stage 2 提案,可能會有變更。


⚠️ 當前狀態

Pipeline Operator 目前是 Stage 2,語法可能會有變更。現在使用需要 Babel:

npm install --save-dev @babel/plugin-proposal-pipeline-operator

為什麼需要 Pipeline Operator?

// 過去:巢狀函式呼叫,內到外閱讀
const result = capitalize(reverse(toUpperCase(name.trim())));

// 我們的思考順序:trim → toUpperCase → reverse → capitalize
// 但程式碼是從內到外:先讀 trim,再讀 toUpperCase...

這個問題叫做「週estan 悖論」(Pyramid of Doom)——巢狀越多,越難閱讀。


提案語法:Hack Pipe

TC39 最終選擇了 Hack pipe(與 Hack 語言類似):

// 用 |> 表達左到右的資料流
const result = name
  |> trim
  |> toUpperCase
  |> reverse
  |> capitalize;

%topic reference(主題引用),代表前一步的結果:

// 沒有引數的函式:直接傳遞結果
name |> trim;  // trim(name)

// 單引數函式:
name |> toUpperCase(%);  // 等於 toUpperCase(name)
// 省略 %:
name |> toUpperCase;     // 同上,% 可省略

// 明確指定 %:
const doubled = 5 |> (x => x * 2);  // 10

// 多引數:
const greeting = ['Hello', 'World']
  |> join(%[0], %[1]);  // 'Hello World'

實際應用

字串處理管道

const processUsername = (input) => input
  |> trim
  |> (s => s.toLowerCase())
  |> (s => s.replaceAll(' ', '_'))
  |> (s => s.normalize('NFC'));

console.log(processUsername('  Alice Smith  '));
// 'alice_smith'

與 Iterator Helpers 結合

// Pipeline Operator + Iterator Helpers:streaming data processing
const result = generateLargeData()  // 返回 Iterator
  |> Iterator.from(%)
  |> %.filter(x => x.active)
  |> %.map(x => x.score)
  |> %.take(10)
  |> %.toArray();

F# vs Hack Pipe 的歷史之爭

TC39 花了十年才決定採用 Hack pipe。這個漫長的過程源於兩種語法的根本分歧:

  • F# pipename |> toUpperCase() — 括弧是函式呼叫語法的一部分
  • Hack pipename |> toUpperCase — 不需要括弧,但引數要用 % 明確指定

F# 語法更直覺,但與 JSX 和 Template Literal 語法有衝突。Hack pipe 最終勝出,因為它避免了這些衝突,而且 % 主題引用讓多引數場景更清晰。


與方法鏈的比較

// 方法鏈:適合方法在同一物件上
const result = users
  .filter(u => u.active)
  .map(u => u.name)
  .slice(0, 10);

// Pipeline:適合不同函式、不同類型的轉換
const result = rawData
  |> trim
  |> validateEmail
  |> normalizeUnicode
  |> hashPassword
  |> storeInDb;

Pipeline Operator 與方法鏈是互補的——根據場景選擇適合的。


總結

Pipeline Operator 是一個** Stage 2 尚未標準化的提案**,但它的未來已經比較明確。如果這個提案達到 Stage 4:

// 就可以用這種乾淨的語法
const result = data |> clean |> transform |> validate;

這是 TC39 新語法深度解析系列的第九篇。下一篇:Import Attributes — 更安全、更明確的模組導入語法。


延伸閱讀


本文基於 TC39 Pipeline Operator 提案(Stage 2)整理,語法可能會有變更。