JavaScript无原生PartialFunction,但可模拟其“定义域限制、条件匹配、可组合”特性:基础版用guard+handler闭包;组合版通过andThen/orElse链式fallback;模式匹配版用对象分支+match方法;需区别于参数预设的partial应用。

JavaScript 本身没有原生的 PartialFunction 类型(那是 Scala 的概念),但我们可以用函数式编程思想模拟其核心行为:**只对特定输入“有定义”、可组合、支持条件匹配与偏应用**。下面给出几种实用、贴近实际需求的实现方案。
基础偏函数:带守卫的单次判断
最简实现是返回一个函数,它内部先检查输入是否满足条件(守卫),满足才执行逻辑,否则不响应(可抛错或返回 undefined):
- 用闭包封装条件和处理逻辑
- 守卫函数(guard)决定“是否定义”
- 典型场景:处理有限枚举、安全解构、类型过滤
const partial = (guard, handler) => (...args) => {
if (guard(...args)) return handler(...args);
// 不抛错,保持“未定义”语义;也可 throw new Error('Not defined')
};使用:
const isPositive = partial(x => x > 0, x => x * 2);<br> isPositive(5); // 10<br> isPositive(-3); // undefined(未定义)
可组合偏函数:andThen 与 orElse
模仿 Scala 的链式行为,让多个偏函数按序尝试,第一个“有定义”的执行并返回结果,否则交由下一个:
-
andThen:当前有定义时,将结果传给下一个函数(类似 map) -
orElse:当前未定义时,尝试备选偏函数(关键!实现 fallback) - 需维护内部状态(guard + handler),因此用类或工厂函数封装
class Partial {
constructor(guard, handler) {
this.guard = guard;
this.handler = handler;
}
apply(...args) {
return this.guard(...args) ? this.handler(...args) : undefined;
}
andThen(next) {
return new Partial(
(...args) => this.guard(...args),
(...args) => next(this.handler(...args))
);
}
orElse(other) {
return new Partial(
(...args) => this.guard(...args) || other.guard(...args),
(...args) => this.guard(...args) ? this.handler(...args) : other.handler(...args)
);
}
}使用:
const doublePos = new Partial(x => x > 0, x => x * 2);<br> const negZero = new Partial(x => x === 0, () => -1);<br> const fallback = doublePos.orElse(negZero);<br> fallback.apply(4); // 8<br> fallback.apply(0); // -1<br> fallback.apply(-2); // undefined
模式匹配风格偏函数(对象字面量 + Symbol)
更贴近函数式语言中“case 模式”的写法,用对象描述多个分支,运行时动态匹配:
立即学习“Java免费学习笔记(深入)”;
- 用
Symbol.for('Partial')标记对象为偏函数 - 每个 key 是守卫函数(或字符串/正则等可判别值),value 是处理器
- 提供统一
match()方法遍历分支 - 适合路由分发、事件类型处理、AST 节点处理等场景
const Partial = Symbol.for('Partial');
<p>const match = (cases) => {
return function(...args) {
for (const [guard, handler] of Object.entries(cases)) {
let ok = false;
if (typeof guard === 'function') ok = guard(...args);
else if (typeof guard === 'string') ok = args[0] === guard;
else if (guard instanceof RegExp) ok = guard.test(args[0]);
if (ok) return handler(...args);
}
};
};</p><p>const handleEvent = match({
'click': () => console.log('clicked'),
'hover': () => console.log('hovered'),
[x => typeof x === 'object' && 'data' in x]: (e) => console.log('custom:', e.data)
});与标准 partial(偏应用)的区别提醒
注意不要混淆:
PartialFunction ≠ partial application(如 _.partial 或 fn.bind)
前者关注“定义域限制”(domain restriction),后者关注“参数预设”(argument fixing)。两者可结合使用,但目标不同:
- 偏应用:固定部分参数,生成新函数(如
add5 = add.bind(null, 5)) - 偏函数:限定输入范围,拒绝非法输入(如 “只处理正数”,其余不响应)
- 实践中常先做偏应用构造 handler,再套上 guard 构成完整偏函数










