手写柯里化,实现柯里化
柯里化,就是将接受多个参数的函数变换成接受一个单一参数的函数。
闭包的应用场景就是函数科里化。(延长变量的生命周期)
参数复用,利用闭包将函数的参数储存起来,等参数达到一定数量时执行函数
fn(x, y) -> fn(x)(y)
上面的代码就是把fn函数做成嵌套函数,外层函数的返回值是内层函数。外层函数调用完之后,能接着调用。
涉及到的概念,高阶函数,闭包,call/apply,argument。
科里化执行函数的核心是:有参数传入时,收集参数,返回函数;收集参数完毕,执行,返回值。
第一种方法:比较容易理解
fn指的是源处理函数,如sum,currArgs 是调用curry时传入的参数列表,比如(1,2)(3)
function curry(fn, currArgs){return function(){ let args = Array.from(arguments); // 首次调用的时候,若未提供最后一个参数currArgs,则不用进行args拼接 if(currArgs !== undefined){ args = args.concat(currArgs) } // 递归调用,判断args的个数,是否与fn的参数相对能,相等了就可以把参数都传给fn,进而输出;否则继续递归调用,一直到两者相等。 if(args.length < fn.length){ // fn.length 是fn函数参数的个数 return curry(fn, args); } return fn.apply(null, args); } } function sum(a, b, c) { console.log(a + b + c); } const fn = curry(sum); fn(1, 2, 3); // 6 fn(1, 2)(3); // 6
第二种方法,
const curry = (fn) => { if (typeof fn !== 'function') { console.log('function') throw Error('No function provided') } return function curriedFn (...args) { // 括号里扩展运算符的作用,是把传过来的参数变成数组。 // 等同于 args = Array.from(arguments); if (fn.length > args.length) { // 未达到触发条件,继续收集参数 return function () { /** * [].slice.call(arguments) 将类数组转化为数组, * 上一行代码的原理是call会将slice方法内部的this就会被替换成arguments, * 并循环遍历arguments,复制到新数组返回,这样就得到了一个复制arguments类数组的数组对象。 * 等同 Array.from(arguments) * 也等同于 Array.prototype.slice.call(arguments) */ return curriedFn.apply(null, args.concat(Array.from(arguments))) } } // apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性. // Function.apply(obj,args)方法能接收两个参数 // obj:这个对象将代替Function类里this对象 // args:这个是数组,它将作为参数传给Function(args-->arguments) return fn.apply(null, args) // args作为参数,被fn调用。 } } const multiply = (x, y, z) => x*y*z; const curryMul = curry(multiply); const result = curryMul(1)(2)(3); // 1*2*3 = 6 console.log('result',result)