SOURCE

// 函数柯里化:f(x, y, z) => h(x)(y)(z)

// 第一步:加法运算柯里化
// add(a, b, c) => curryAdd(a)(b)(c)

let sum = 0;
function add() {
    sum += Array.from(arguments).reduce((x, y) => x + y);
    add.toString = () => sum; // console.log时实际调用的是Function.toString()
    return add;
}

// 第二步:利用闭包实现纯函数式的柯里化
function curryAdd() {
    // 第一次调用时,就要对参数求和并保存到total中
    let total = Array.from(arguments).reduce((x, y) => x + y);
    // 利用闭包特性,保存total
    const _add = function () { // 注意此处不能写成箭头函数
        total += Array.from(arguments).reduce((x, y) => x + y);
        return _add;
    }
    _add.toString = () => total;
    return _add;
}

// 第三步:把对参数的操作放在最后
function curryAddAdvanced() {
    // 把参数保存到一个数组里
    const arr = Array.from(arguments);
    // 利用闭包特性,保存total
    const _add = function () { // 注意此处不能写成箭头函数
        arr.push(...Array.from(arguments));
        return _add;
    }
    _add.toString = () => Array.from(arr).reduce((x, y) => x + y);
    return _add;
}

// 测试加法运算柯里化
console.log("add", add(1, 2, 3)(4)(6, 7))
console.log("curryAdd", curryAdd(1)(2, 3)(4)(6, 7), curryAdd(1, 2, 3)(4)(6, 7));
console.log("curryAddAdvanced", curryAddAdvanced(1)(2, 3)(4)(6, 7), curryAddAdvanced(1, 2, 3)(4)(6, 7));


// 第四步:将柯里化操作抽象为封装函数
function fnToCurry(fn) {
    const curry = function () {
        const arr = [];
        // 第一次调用时,把参数保存到一个数组里
        arr.push(...Array.from(arguments));
        // 利用闭包特性,保存total
        const _fn = function () { // 注意此处不能写成箭头函数
            arr.push(...Array.from(arguments));
            return _fn;
        }
        _fn.toString = () => fn(...arr);
        return _fn;
    }
    return curry;
}

// 测试柯里化封装函数
// 测试1:乘法运算
function f1() {
    return Array.from(arguments).reduce((x, y) => x + y);
}
const f2 = fnToCurry(f1);
console.log("柯里化", f2(1, 2, 3), f2(1)(2, 3), f2(1)(2)(3));

// 延迟执行
// 假设当传入参数包含"exec"时,再执行
// 如fn(a)(b)(c)("exec"),当最后再执行
function fnToDelayCurry(fn) {
    const arr = [];
    const curry = function () {
        // 第一次调用时,把参数保存到一个数组里
        arr.push(...Array.from(arguments));
        // 利用闭包特性,保存total
        const _fn = function () { // 注意此处不能写成箭头函数
            // 当输入的参数中有exec标志时,立即执行
            // 这里包含exec的参数不保存到arr中,若要保存把else中的push挪到外层即可
            if (Array.from(arguments).indexOf("exec") > -1) {
                _fn.toString = () => fn(...arr);
            } else {
                _fn.toString = Function.toString;
                arr.push(...Array.from(arguments));
            }
            return _fn;
        }
        return _fn;
    }
    return curry;
}

function delayFn() {
    const args = Array.from(arguments);
    return args.join("~");
}
console.log("不会执行函数", fnToDelayCurry(delayFn)(1)(2)(3)(4, 5)); // 这里打印的是函数
console.log("最后执行函数", fnToDelayCurry(delayFn)(1)(2)(3)(4, 5)("exec")); // 这里真正执行
console 命令行工具 X clear

                    
>
console