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