//函数柯理化 其本质是下降通用性,提升适用性,实际上是对闭包的极致应用 //原理:利用闭包保存一部分参数,返回一个包含了一部分参数的闭包。 //适用场景: ... 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");