浅谈JavaScript函数柯里化

什么是currying/柯里化


  1. 百度百科中是这么解释的:柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
  2. 忍者秘籍中是这么解释的:在一个函数中首先填充几个参数(然后再返回一个新函数)的技术称为柯里化(Currying)。

如果看这些概念你不是特别清楚那么我们接下来看一个实例:

let add1 = function(a,b,c){
    return a+b+c;
}
let add2 = function(a){//函数柯里化
    return function(b){
        return function(c){
            return a+b+c;
        }
    }
}
console.log(add1(1,2,3));//6
console.log(add2(1)(2)(3));//6

是不是感觉和闭包有点类似,恩 其实实质利用的就是闭包的概念,本质上讲柯里化(Currying)只是一个理论模型,柯里化所要表达是:如果你固定某些参数,你将得到接受余下参数的一个函数。

柯里化实例


当然,柯里化的参数是不固定的,假设我现在有n个数需要求和操作我们应该怎么写

let add = function () {
    let _args = [];
    return function () {
        if (arguments.length === 0) {
            return _args.reduce(function (a, b) {
                return a + b;
            });
        }
        [].push.apply(_args, [].slice.call(arguments));
        return arguments.callee;
    }
   };
let sum = add()

sum(1,2)(3);    // 调用形式灵活,一次调用可输入一个或者多个参数
console.log(sum());   // 6(最后在进行计算输出) 

上面 add是柯里化了的函数,它返回一个新的函数,新的函数可接收新的参数,延迟到最后一次计算。

基础知识讲解


arguments

函数有个内置的对象 arguments 对象。argument 对象包含了函数调用的参数数组。

arguments.callee

arguments.callee该属性是一个指针,指向拥有这个arguments对象的函数。由于严格模式下不能使用arguments.callee所以,我们可以改进一下上面的add函数。

let add = function () {
    let _args = [];
    return function fn () {
        if (arguments.length === 0) {
            return _args.reduce(function (a, b) {
                return a + b;
            });
        }
        [].push.apply(_args, [].slice.call(arguments));
        return fn;
    }
   };
let sum = add()

sum(1,2)(3);    // 调用形式灵活,一次调用可输入一个或者多个参数
console.log(sum());   // 6(最后在进行计算输出) 

[].push.apply(_args, [].slice.call(arguments));

这个方法等同于Array.prototype.push.apply(_args,Array.prototype.slice.call(arguments));这个方法实现了将arguments合并到 _args中与 _args = _args.concat([].slice.call(arguments));类似。

封装柯里化函数


我们既然知道了柯里化函数是什么,那么我们可以将它封装成一个函数

let currying = function (callback){//参数中放入一个回调函数
    let _args = [];//声明一个参数数组
    return function fn(){
        if(arguments.length===0){
            return callback.apply(this,_args);
        }
        _args = _args.concat([].slice.call(arguments));
        return fn;
    }
};

使用

let add = function () {
    let sum = 0;
    for (let i = 0, c; c = arguments[i++];) {
        sum += c;
    }
    return sum;
};

let sum = currying(add);

sum(1,2)(3);
console.log(sum());//6

当然,当大家看到这里时是不是觉得柯里化好像在平时用不上,那么大家觉得bind函数用的多吗?其实bind函数你们就可以看成另一种柯里化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章