函数柯理化

//函数柯理化  其本质是降低通用性,提高适用性,其实是对闭包的极致应用
//原理:利用闭包保存一部分参数,返回一个包含了一部分参数的闭包。
//适用场景: ...

function connect(a, b, c, d,e,f,g) {
    console.log(`${a}-${b}-${c}-${d}-${e}-${f}-${g}`);
}

//在闭包中,A闭包 由 B函数生成
//使用闭包可以引用函数的变量对象这一性质
//把闭包中存的变量和闭包接受的实参组合起来,传入目标函数
//简易版
function simpleCurry(fn){
    let args = [].slice.call(arguments, 1);
    return function () {
        fn.apply(this, args.concat([].slice.call(arguments)))
    }
}

//只可以分成两步,如果要可以分成任意层,就得用递归了
// simpleCurry(connect, 1, 2,5,67,8,4)(3);
// simpleCurry(connect, 1)(2, 3,4,5,6, 28);

//完整版,接受N层闭包,由于层数不定,递归也必须用到
//递归的过程中不断的 聚集参数,直到参数达到目标函数需要的个数,就执行函数
//如何知道函数接受的理想参数个数  fn.length
function curry(fn, args){
    let length = fn.length; //目标函数理想的参数个数
    let allArgs = args || [];
    return function () {
        let _args = [].slice.apply(arguments);
        let _allArgs = allArgs.concat(_args)
        //未达到理想参数个数就继续聚集参数, 达到了参数的个数,就可以运行目标函数
        if (_allArgs.length < length){
            //聚集参数的过程
            return curry.call(this, fn, _allArgs)
        }
        else{
            fn.apply(this, _allArgs);
        }
    }
}

curry(connect)(2, 3, 4, 5)(6, 1)(2);

//如果不想按顺序传入,则可以先用占位符,后面再填入数据
//比如
/**
 * 
let fn = curry(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", _, "c")("b") // ["a", "b", "c"]
 * 
 * 
 */
let _;
function curry2(fn, args){
    let allArgs = args || [];
    let length = fn.length;
    return function () {
        let _args = [].slice.call(arguments);
        let _allArgs = [].slice.call(allArgs);
        //在这里来调整参数的位置, 如果前面有占位符就向前补位

        if (_args.indexOf(_) !== -1){
            //有占位符  就直接concat
            _allArgs = _allArgs.concat(_args);
        }
        else{
                //没有占位符,说明这段参数可以向前补位
            _allArgs.forEach((v, i) => {
                if (v === _ && _args.length != 0) {
                    _allArgs.splice(i, 1, _args.shift());
                }
            })
            //剩下的还是添加进参数里面
            if (_args.length != 0){
                _allArgs = _allArgs.concat(_args);
            }
        }
            //是否达到理想参数个数  以及是否还含有空位
        if (_allArgs.length < length || _allArgs.indexOf(_) !== -1){
            //继续聚集参数
            return curry2.call(this, fn, _allArgs);
        }
        else{
            fn.apply(this, _allArgs);
        }
    }
}

curry2(connect)(2, _, 4, 5)(_, 1)(_)("占位1", "占位2")("占位3");
posted @ 2019-04-26 16:36  寻路、  阅读(372)  评论(0编辑  收藏  举报