函数柯里化

函数柯里化

在数学和计算机科学中,柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术。而对于JavaScript语言来说,我们通常说的柯里化函数的概念,与数学和计算机中的柯里化的概念并不完全一样。

对于已经柯里化后的函数来说,当接收的参数数量原函数的形参数量相同时,执行原函数;当接收的参数数量小于原函数的形参数量时,返回一个函数用于接收剩余的参数,直至接收的参数数量与形参数量一致,执行原函数。

柯里化的定义:接收一部分参数,返回一个函数接收剩余参数,接受足够参数后,执行原函数。

普通版

function total(a,b,c,d,e){
    return a + b + c + d + e
}

function curry(fn,...args){
    let len = fn.length
    return function(...rest){
        let params = [...args,...rest]
        if(params.length >= len){
            return fn.apply(this,params)
        }
        return curry.call(this,fn,...params) // 注:此处使用call绑定this 为了调用curry方法入参fn外多个参数,而不是数组参数rest。
    }
}

函数柯里化经典面试题

实现(不限制参数个数)

var a = add();    // 0
console.log(a); // '0';
typeof a; // 'function'
var b = add(1)(2);    // 3
var c = add(1)(2)(3); // 6
var d = add(1)(2)(3)(4)(5); // 15
var e = c + b; // 9
typeof e; // number
// 注意,方法前都有一个+
console.log(+add(1)(2));// 3
console.log(+add(1)(2, 3));// 6
console.log(+add(1)(2, 3)(4));// 10

  

function add(...args){
    let arr = [...args]
    let _adder = function(...rest){
        arr.push(...rest)
        return _adder
    }
    _adder.toString = function(){
        return arr.reduce((x,y) => x + y)
    }
    return _adder
}

占位符版

function _curry(fn,length,holder,args = [],holders = []){
    return function(..._args){
        //将参数复制一份,避免多次操作同一函数导致参数混乱
        let params = args.slice();
        //将占位符位置列表复制一份,新增加的占位符增加至此
        let _holders = holders.slice();
        //循环入参,追加参数 或 替换占位符
        _args.forEach((arg,i)=>{
            //真实参数 之前存在占位符 将占位符替换为真实参数
            if (arg !== holder && holders.length) {
                let index = holders.shift();
                _holders.splice(_holders.indexOf(index),1);
                params[index] = arg;
            }
            //真实参数 之前不存在占位符 将参数追加到参数列表中
            else if(arg !== holder && !holders.length){
                params.push(arg);
            }
            //传入的是占位符,之前不存在占位符 记录占位符的位置
            else if(arg === holder && !holders.length){
                params.push(arg);
                _holders.push(params.length - 1);
            }
            //传入的是占位符,之前存在占位符 删除原占位符位置
            else if(arg === holder && holders.length){
                holders.shift();
            }
        });
        // params 中前 length 条记录中不包含占位符,执行函数
        if(params.length >= length && params.slice(0,length).every(i=>i!==holder)){
            return fn.apply(this,params);
        }else{
            return _curry.call(this,fn,length,holder,params,_holders)
        }
    }
}
posted @ 2020-06-02 21:18  671_MrSix  阅读(197)  评论(0)    收藏  举报