柯里化学习记录

127 阅读1分钟

概念:

将多个参数的函数转化为一个参数且返回一个新函数的技术

分析:

(1) 多个参数=>1个参数

(2) 返回一个新函数

代码:

function curry(fn, args) {
    var slice = Array.prototype.slice;      // 缓存数组的 slice 方法
    var length = fn.length;                 // 函数参数的长度
    var args = args || [];                  // 闭包保存参数列表
    return function() {
        var _args = slice.call(arguments);  // 获取参数列表
        var newArgs = args.concat(_args);   // 新的参数与上一次的参数拼接起来

        if(newArgs.length < length) {
            /**如果传入的参数列表长度还没有超过函数定义时的参数长度,迭代 curry 函数
             * 自己调用自己,将保存的参数传递到下一个柯里化函数
             * */ 
            return curry.call(this, fn, newArgs);
        } else {
            /**如果传入的参数列表长度已经超过函数定义时的参数长度,就执行。
            */
            return fn.apply(this, newArgs);
        }
    }
}
function multiFn(a, b, c, d) {
    return a * b * c * d;
}
var multi = curry(multiFn);
var result = multi(2)(3)(4)(5);
console.log('result :>> ', result);

核心思路:

function curry(fn, ...args) { 
	...
  	return function(...args2) {
    		var newArgs = [...args, ...args2];
    		if(fn.length > newArgs.length) {
      			return curry.call(this, fn, newArgs)
    		} else {
      			return fn.call(this, newArgs)
    		}
  	}
}

练习:

/**
 * 实现 addFn(1)(2)(3)  结果:6
 * 实现 addFn(1,2)(3)   结果:6
 * 实现 addFn(1,2,3)    结果:6
 * */ 
function addFn() {
    // 第一次调用 addFn 函数时,将参数保存在数组中
    var _args = Array.prototype.slice.call(arguments);

    /**内部声明一个函数,利用闭包,保存参数
     * @return _fn  返回自己,如果再调用函数, addFn(1,2)(3)这个就会调用两次
     * */ 
    var _fn = function(...args) {
        _args.push(...args);
        return _fn
    }

    // 利用 toString 隐式转换,执行时隐式转换,返回计算结果
    _fn.toString = function() {
        return _args.reduce(function(total, item, index) {
            return total + item
        }, 0)
    }

    // 返回 _fn 函数
    return _fn
}
var r1 = addFn(1,2,3);
var r2 = addFn(1,2)(3);
var r3 = addFn(1)(2)(3);
console.log('r1 :>> ', r1);
console.log('r2 :>> ', r2);
console.log('r3 :>> ', r3);

参考资料:

www.zhangxinxu.com/wordpress/2…