当你的代码库还很小的时候,一切都清清楚楚、直来直去。可一旦项目膨胀,函数像藤蔓一样彼此勾连,层层嵌套把本来简单的逻辑搅成一锅粥。这时函数式编程就开始显神通了。我最初入门时靠的是一个优雅的小工具——compose。它把混乱的嵌套调用改造成有序的变换序列,看起来就顺眼多了。而现在,我们无需再额外写工具,也能做到同样甚至更清晰的表达。
你不再把函数一层层包起来,而是用一个简单的运算符从左到右把它们串起来。先上手,再解释。
把“套娃式”调用拉平成管道
在 ES2025 中,有一个被提案的运算符,用来把嵌套且凌乱的函数调用改写成直观易读的流水线。它能把那些“里三层外三层”的表达拆解成一条人人都能跟得上的数据管道。目前它处于 TC39 Stage 2,意味着正在积极推进,但尚不适合直接用于生产。管道运算符(|>)允许你从左到右串联操作,而不是传统的“从最里层往外读”。把它想成数据的传送带:每一步拿到上一步的结果,继续变换。
// 现在的写法——嵌套调用
const result = h(g(f(x)));
// 堆代码 duidaima.com
// 使用管道运算符
const result = x |> f |> g |> h;
它的精妙之处在于占位符机制:用一个特殊的占位符,精确标注“上一步的值应该放到哪里”。
// 传统嵌套(读起来费劲)
const result = formatCurrency(
calculateTax(
applyDiscount(getPrice(product), 10),
0.08
)
);
// 管道 + 占位符(清楚、线性)
const result = product
|> getPrice(%)
|> applyDiscount(%, 10)
|> calculateTax(%, 0.08)
|> formatCurrency(%);
有了占位符,你就能精准控制数据的落点。正是占位符把管道运算符从“锦上添花”推到了“不可或缺”。
const data = users
|> %.filter(u => u.active)
|> %.map(u => u.name)
|> { count: %.length, names: % }
|> JSON.stringify(%, null, 2);
示例 1:API 数据处理
// 之前:层层嵌套,读写都吃力
const processUserData = (response) => {
return response.users
.map(user => ({
...user,
fullName: formatName(user.firstName, user.lastName),
isActive: checkStatus(user.status, 'active')
}))
.filter(user => user.isActive)
.sort((a, b) => a.fullName.localeCompare(b.fullName));
};
// 之后:清晰的管道
const processUserData = (response) => {
return response.users
|> %.map(user => ({
...user,
fullName: formatName(user.firstName, user.lastName),
isActive: checkStatus(user.status, 'active')
}))
|> %.filter(user => user.isActive)
|> %.sort((a, b) => a.fullName.localeCompare(b.fullName));
};
示例 2:表单校验流水线
const validateForm = (formData) => {
return formData
|> sanitizeInput(%)
|> validateRequired(%, ['email', 'password'])
|> validateEmail(%.email) ? % : { ...%, errors: [...%.errors, 'Invalid email'] }
|> validatePassword(%.password) ? % : { ...%, errors: [...%.errors, 'Weak password'] }
|> %.errors.length === 0
? { valid: true, data: % }
: { valid: false, errors: %.errors };
};
示例 3:字符串处理链
// 把用户输入变成 URL slug
const createSlug = (title) => {
return title
|> %.toLowerCase()
|> %.trim()
|> %.replace(/[^\w\s-]/g, '')
|> %.replace(/\s+/g, '-')
|> %.substring(0, 50)
|> %.replace(/-+$/, '');
};
注意到没有?占位符 % 让你可以直接在管道值上调用方法。这份灵活性正是我们一直缺少的。
如何在项目里先用起来
虽然管道运算符还停留在 Stage 2,但你可以通过 Babel 7.15+ 先行体验。
安装 Babel 插件:
npm install --save-dev @babel/plugin-proposal-pipeline-operator
配置 .babelrc:
{
"plugins": [
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "hack",
"topicToken": "%"
}
]
]
}
完成后,你就可以愉快地写管道代码,由 Babel 将其转译为当前浏览器可执行的形式。我已经在生产中以转译方式使用了数月,产物干净、性能稳定。