js的柯里化

117 阅读2分钟

​持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

JS的函数柯里化理解

1、什么是柯里化?

柯里化(currying):是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术;

实现一个简单的例子:

// 普通函数
function count(a:number,b:number){
•    return a + b;
}
// 柯里化后
function curryingCount(a:number){
•    return function(b:number){
•        return a + b;
•    }
}
console.log(count(2,2))
console.log(curryingCount(2)(2));

看完这个简单的例子,你可能会觉得这样封装反而没之前方便了,那么请看下面一个例子

// 普通函数封装

function counts(a:string,b:string){
​
    return a + b;
​
}
​
console.log(counts('小明','吃饭'));
​
console.log(counts('小明','睡觉'));
​
console.log(counts('小明','上学'));

/**

  • 小明吃饭

    小明睡觉

    小明上学

*/

// 从这三个函数调用可以发现,第一个参数重复了,普通函数封装又不得不每次都带上这个参数

// 柯里化后


function curringCounts(a:string){
​
    return function(b:string){
​
        return a + b;
​
    }
​
}
​
let names = curringCounts('小明')
​
let namet = curringCounts('老王')
​
console.log(names('笑哈哈'));
​
console.log(names('算数学'));
​
console.log(namet('住隔壁'));

/**

  • 小明笑哈哈

    小明算数学

    老王住隔壁

*/

这个就是柯里化的优点之一,参数复用(利用闭包的原理,让前面传输的参数一直存在)

js的bind函数的实现机制就是柯里化的封装


Function.prototype.bind = function (context){
•    var that = this
•    var args = Array.prototype.slice.call(arguments,1)
•    return function(){
•        return that.apply(context,args)
•    }
}

这也是柯里化的优点之一:延迟运行(利用闭包将函数的定义和执行环境分开)

接下来的一个例子


var on = function(isSupport:any, element:any, event:any, handler:any){
    isSupport = isSupport || document.addEventListener
    if (isSupport){
        return element.addEventListener(event,handler,false);
    }else{
        return element.attachEvent('on'+event,handler)
    }
}

这是柯里化的优点之一:提前确认(利用柯里化特性对某些全局方法进行改写,就是提前确定会走哪个方法,避免每次都进行判断)

通用封装方法


var currying = function (fn:any){
    //  args 获取第一个方法内全部参数
    var args = Array.prototype.slice.call(arguments,1)
    return function(){
        var newArgs = args.concat(Array.prototype.slice.call(arguments))
        return fn.apply(this,newArgs)
    }
}

支持多参数传递


function progressCurring(fn:any,args:any){
    var that = this
    var len = fn.length;
    var args = args || []
    return function(){
        var _args = Array.prototype.slice.call(arguments)
        Array.prototype.push.apply(args,_args);
        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if(_args.length<len){
            return progressCurring.call(that,fn,_args);
        }
        return fn.apply(this,_args)
    }
}

经典面试题

function add() {

​ const _args = [...arguments];

​ function fn() {

​ _args.push(...arguments);

​ return fn;

​ }

​ fn.toString = function() {

​ return _args.reduce((sum, cur) => sum + cur);

​ }

​ return fn;

}

console.log(add(1,2,3)(4));