柯里化

109 阅读2分钟

含义

把接收多个参数的函数变换成接收一个单一参数(最初函数的第一个参数)的函数,并返回接受剩余的参数而且返回结果的新函数的技术。 柯里化又称部分求值,字面意思就是不会立刻求值,而是到了需要的时候再去求值。

作用

缓存参数调用后的函数

function volume (l, w, h) {
	return l * w * h
}

// 碰巧你仓库里的所有物品都是100m高。你会看到你不停地用h=100来调用这个函数:
volume(200, 30, 100) // 2003000
volume(32, 45, 100) // 144000
volume(2322, 232, 100) // 53870400

// 为了解决这个问题,你把volume函数柯里化(像我们之前做过的):
function volume (h) {
	return (w) => {
		return (l) => {
			return l * w * h
		}
	}
}

// 我们能给同类物品定义一个特殊函数:
const hCylinderHeight = volume(100)
hCylinderHeight(200)(30) // 600000
hCylinderHeight(2322)(232) // 53870400

代码实现

只能接受一个参数的柯里化

    function curry_one(fn) {
        if (fn.length <= 1) return fn;

        // 这是我一开始的实现
        // 后来发现 rest 是多余的,下面这样就行了,fn.length 多处用到,可以提出来
        // const generator = (args) => (args.length === fn.length ? fn(...args) : arg => generator([...args, arg]));
        const generator = (args, rest) => (
            rest == 0 ? 
            fn(...args) : 
            arg => generator([...args, arg], rest - 1)
        );

        return generator([], fn.length);
    };

可以接受多个参数的柯里化

    function curry_multi(fn) {
        const generator = (...args) => {
            return 
                    (args.length === fn.length) ?

                    fn(...args) : 

                    (..._args) => generator(...args, ..._args)
        } 
        return generator;
    }




    const sum = (a, b, generator) => a + b + generator;
    const curriedSum = curry_one(sum);
    const res = curriedSum(1)(2)(3)
    console.log(res); // 6

    const log = (a, b, generator) => {
        console.log(a, b, generator);
    };
    const curriedLog = curry2(log);
    curriedLog('a')('b')('generator'); // a b generator

自己实现的

/**
 * 返回一个函数,
 * 当该函数接受到的参数和为柯里化函数的参数总数时,触发柯里化函数,
 * 否则用闭包的试试保留柯里化的参数
 * @param {*} callback  需要柯里化的函数 
 */
function cury(callback){
    let len = callback.length;
    let saveArg = [];
    function fn(...arg){
        saveArg  = saveArg.concat(arg);
        if(saveArg.length === len) {
            return callback(...saveArg);
        }
        else {
            return fn;
        }
    }
    return fn;
}

function add(a,b,c,d) {
    console.log(a,b,c,d);
}
let test = cury(add);
test(1)(2)(2)(4)