摘要:// 需求:将一个字符串去首尾空格,转为大写,然后截取前5个字符const text = " hello world ";const result = text.trim.toUpperCase.substring(0, 5); // 链式调用,还算优雅//
前端的同学们,你们是否曾被这样的代码折磨过?
// 需求:将一个字符串去首尾空格,转为大写,然后截取前5个字符const text = " hello world ";const result = text.trim.toUpperCase.substring(0, 5); // 链式调用,还算优雅// 但如果这些是独立的函数呢?const trim = (str) => str.trim;const toUpper = (str) => str.toUpperCase;const substring = (str, start, end) => str.substring(start, end);// 为了完成同样的需求,代码变成了这样:const resultNested = substring(toUpper(trim(text)), 0, 5);substring(toUpper(trim(text)), 0, 5) 这行代码,代码的执行顺序是从内到外:trim -> toUpper -> substring。
而我们的阅读顺序却是从左到右。这种“反人类”的阅读体验,就是我们常说的函数嵌套地狱。
那么,有没有一种既能保持链式调用的优雅,又能适用于独立函数的方案呢?
ECMAScript 2025 (ES2025) 将为我们带来一个“王炸”级的新特性——管道操作符 (Pipeline Operator) |>。
管道操作符 |> 的灵感来源于 F#、Elixir 以及 Unix/Linux 的 Shell 命令。
它的核心思想非常简单:将左侧表达式的结果,作为右侧函数的第一个参数传入。
换句话说,x |> f 等价于 f(x)。
现在,让我们用管道操作符来重写刚才的噩梦代码:
import { trim, toUpper, substring } from './utils'; // 假设函数在别处const text = " hello world ";// 使用管道操作符const result = text |> trim |> toUpper |> substring(?, 0, 5); // 注意这里的 ? 或 %// 等一下,substring 有多个参数怎么办?这看起来是不是如丝般顺滑?代码的阅读顺序和执行顺序完全一致,从上到下,从左到右,就像一条清晰的数据处理流水线。
你可能已经注意到了 substring(?, 0, 5) 这个奇怪的写法。substring 函数需要三个参数 (str, start, end),但管道操作符默认只能传递一个参数。
为了解决这个问题,TC39 委员会最终选择了 “Hack 风格”的管道提案。这种风格引入了一个占位符,通常是 ? 或 % (目前提案中 % 的呼声更高)。
占位符代表的就是管道左侧传来的值。
这给了我们极大的灵活性:例如与 await 结合:
async function getUser(id) { const user = await fetch(`https://api.example.com/users/${id}`) |> await ?.json; return user;}占位符的引入,让管道操作符从一个只能处理单参数函数的“甜点”,一跃成为能够处理任何函数和表达式的“瑞士军刀”。
截至目前,管道操作符还未获得浏览器和 Node.js 环境原生支持,但我们已经可以通过 Babel 提前尝鲜!
管道操作符 |> 无疑是近年来 JavaScript 语言最令人兴奋的提议之一,它并非创造了新的功能,而是提供了一种更优雅、更直观的代码组织方式。
它将函数式编程中的组合思想以一种极其简洁的语法带入 JavaScript,有望从根本上改变我们编写数据处理逻辑的方式。
来源:不秃头程序员