curry.js

/* eslint-disable prefer-rest-params */
import { arrayProtoSlice, mathMax } from './internals/native';
import isUndefined from './isUndefined';
import toInteger from './toInteger';
const PLACEHOLDER = {
    __ut2_curry_ph__: null
};
/**
 * 创建一个函数。该函数接受 `func` 参数,在提供的参数数量达到 `arity` 后调用 `func` 并返回其结果。
 *
 *  `curry._` 或 `curry.placeholder` 可用作参数的占位符。
 *
 * @function
 * @alias module:Function.curry
 * @since 1.8.0
 * @param {Function} func 需要柯里化的函数。
 * @param {number} [arity] 指定参数数量。默认值为 `func.length`。
 * @returns {Function} 新的柯里化函数。
 * @example
 *
 * function abc(a, b, c){
 *   return [a, b, c];
 * }
 *
 * var curried = curry(abc);
 *
 * curried(1)(2)(3); // [1, 2, 3]
 *
 * curried(1, 2)(3); // [1, 2, 3]
 *
 * curried(1, 2, 3); // [1, 2, 3]
 *
 * curried(1)(curry._, 3)(2); // [1, 2, 3]
 *
 * curried(curry._, curry._, 3)(curry._, 2)(1); // [1, 2, 3]
 *
 */
const curry = function (func, arity) {
    arity = isUndefined(arity) ? func.length : mathMax(toInteger(arity), 0);
    function wrap() {
        let args = arrayProtoSlice.call(arguments);
        const context = this;
        function inner() {
            const argsInner = arrayProtoSlice.call(arguments);
            for (let i = 0; i < args.length; i++) {
                args[i] = args[i] === PLACEHOLDER && argsInner.length > 0 ? argsInner.shift() : args[i];
            }
            args = args.concat(argsInner);
            const realArgsLength = args.filter((arg) => arg !== PLACEHOLDER).length;
            if (realArgsLength >= arity) {
                return func.apply(context, args);
            }
            return inner;
        }
        return inner();
    }
    return wrap;
};
curry.placeholder = curry._ = PLACEHOLDER;
export default curry;