函數柯理化

//函數柯理化  其本質是下降通用性,提升適用性,實際上是對閉包的極致應用
//原理:利用閉包保存一部分參數,返回一個包含了一部分參數的閉包。
//適用場景: ...

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");
相關文章
相關標籤/搜索