Skip to content

函数柯里化实现

描述

柯里化(Currying)是将接受多个参数的函数转换为接受一个参数的一系列函数的技术。

核心原理

  1. 收集参数
  2. 参数不足时返回新函数继续收集
  3. 参数足够时执行原函数

实现代码

基础版(固定参数数量)

js
function curry(fn) {
    const arity = fn.length;

    return function curried(...args) {
        if (args.length >= arity) {
            return fn.apply(this, args);
        }
        return function (...args2) {
            return curried.apply(this, [...args, ...args2]);
        };
    };
}

完整版(支持不定参数)

js
function curry(fn, ...args) {
    return function (...args2) {
        const allArgs = [...args, ...args2];
        if (allArgs.length >= fn.length) {
            return fn.apply(this, allArgs);
        }
        return curry(fn, ...allArgs);
    };
}

简化版(参数够了就调用)

js
function curry(fn) {
    return function (...args) {
        if (args.length >= fn.length) {
            return fn(...args);
        }
        return (...args2) => fn(...args, ...args2);
    };
}

带占位符的版本

js
function curry(fn) {
    const allArgs = [];

    function curried(...args) {
        allArgs.push(...args);

        if (allArgs.length >= fn.length) {
            const result = fn(...allArgs);
            allArgs.length = 0; // 重置
            return result;
        }

        return curried;
    }

    curried.reset = () => {
        allArgs.length = 0;
    };

    return curried;
}

使用示例

js
// 普通函数
function add(a, b, c) {
    return a + b + c;
}

const curriedAdd = curry(add);

// 逐步传参
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
console.log(curriedAdd(1, 2, 3)); // 6

// 实际应用:预设配置
const fetchWithAuth = curry((url, headers, body) => {
    return fetch(url, { ...headers, ...body });
});

const fetchWithToken = fetchWithAuth("/api/user", { Authorization: "Bearer token" });
const post = fetchWithToken({ method: "POST" });
const get = fetchWithToken({ method: "GET" });

// 网络请求
const request = curry((method, url, data) => {
    console.log(`${method} ${url}`, data);
});

const getRequest = request("GET");
const postRequest = request("POST");

getRequest("/users"); // GET /users undefined
postRequest("/users", { name: "张三" }); // POST /users { name: '张三' }

反柯里化

描述

反柯里化(Uncurrying)是将接受单一参数的函数转换为接受多个参数的函数。

实现代码

js
Function.prototype.uncurry = function () {
    const fn = this;
    return function (...args) {
        return fn.apply(args.shift(), args);
    };
};

// 或者
Function.prototype.uncurry = function () {
    const fn = this;
    return Function.apply.bind(fn);
};

使用示例

js
const push = Array.prototype.push.uncurry();
const arr = [1, 2];

push(arr, 3, 4);
console.log(arr); // [1, 2, 3, 4]

// 类似 Function.call
const call = Function.prototype.call.uncurry();
call(console.log, null, "hello"); // 'hello'

柯里化 vs 反柯里化对比

特性柯里化反柯里化
方向多参转单参单参转多参
目的预设参数扩展方法适用范围
应用函数式编程OOP 向函数式过渡