JavaScript函数组合与柯里化

柯里化将多参函数转化为单参函数链,便于参数复用;函数组合通过pipe或compose连接函数,实现数据流式传递;二者结合可提升代码的模块化与可读性。

函数组合与柯里化是函数式编程中的两个核心概念,它们能帮助我们写出更简洁、可复用、易测试的JavaScript代码。理解并掌握这两个技巧,可以显著提升代码的表达力和灵活性。

什么是柯里化(Currying)

柯里化是指将一个接受多个参数的函数转换为一系列只接受单个参数的函数。每次调用返回一个新的函数,直到所有参数都被传入,最终执行原函数。

例如,原本调用方式为 add(a, b, c),柯里化后可以写成 add(a)(b)(c)

常见实现方式:

  • 手动实现一个简单的柯里化函数:

function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...nextArgs) {
return curried.apply(this, args.concat(nextArgs));
};
}
};
}

使用示例:

function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
curriedAdd(1)(2)(3); // 6
curriedAdd(1, 2)(3); // 6

柯里化的好处在于参数的逐步积累,便于创建预设部分参数的“偏应用函数”。

什么是函数组合(Function Composition)

函数组合指的是将多个函数连接起来,前一个函数的输出作为下一个函数的输入。在数学中表示为 f(g(x)),在JavaScript中我们可以封装这个过程。

从右到左组合的实现:

  • 使用 reduce 反向累积执行:

function compose(...fns) {
return function(value) {
return fns.reverse().reduce((acc, fn) => fn(acc), value);
};
}

从左到右组合(更符合阅读习惯):

function pipe(...fns) {
return function(value) {
return fns.reduce((acc, fn) => fn(acc), value);
};
}

示例:

const toUpper = str => str.toUpperCase();
const exclaim = str => str + '!';
const say = pipe(toUpper, exclaim);
say('hello'); // "HELLO!"

组合让我们可以把小而纯的函数像积木一样拼接起来,构建复杂逻辑而不失清晰性。

柯里化与组合结合使用

柯里化让函数更容易参与组合。因为单参数函数天然适合管道传递数据。

例如,写一个通用的 map 函数并柯里化它:

const map = fn => arr => arr.map(fn);
const double = x => x * 2;
const data = [1, 2, 3];
map(double)(data); // [2, 4, 6]

现在可以无缝接入组合:

const process = pipe(
map(double),
arr => arr.filter(x => x > 3)
);
process([1, 2, 3, 4]); // [4, 6, 8]

这种风格让代码更具声明性,关注“做什么”而非“怎么做”。

基本上就这些。柯里化和函数组合配合使用,能让JavaScript代码更加模块化和可维护。虽然初看略显抽象,但一旦习惯,你会发现自己越来越倾向于写出高阶、可复用的函数结构。不复杂但容易忽略。