js手写题 compose 和 curry 的简单写法和理解

335 阅读2分钟


小二,上酒!

天涯的渡口, 一人陪马儿清瘦, 多么富有, 天下了心中。

compose函数

当一个函数的参数是另一个函数的执行结果的时候,可以使用compose函数 例如:

function add(num){
    return num + num;
} 

function multiply(num){
    return num * num;
}

//有以上两个函数,如果我们想先执行add函数,再用add函数的执行结果去执行multiply函数

//我们可能会这样做
const addRes = add(10);
const mRes = multiply(addRes);

//或者这样
const res = multiply(add(10));

console.log(res) //400

compose的写法:

function compose(){
    //拿到参数数组
    const args = [].slice.call(arguments);
    return function (num){
        //利用数组的reduce方法,每个cb就是传进来的方法
        //res是方法的执行结果,第一次循环res是传递进来的num 也就是10
        return args.reduce((res,cb)=>{
            return cb(res)
        },num)
    }
}
const res = compose(add,multiply)(10)
console.log(res) //400

compose的好处是:
当你理解它的执行流程时,看起来代码更简洁、清晰、方便阅读。我们只需要把函数传递给compose,其余的交给compose来做就好。
想一想如果要执行的函数更多的时候:

//普通写法可能是:
const res = d(c(b(a(10))))
//compose的写法是:
const res = compose(a,b,c,d)(10);

curry函数 又叫函数科里化

//当有一个add函数:

const add = (a,b,c,d) => {//为了方便阅读就不写成一行了
    return a + b + c + d;
}

//普通调用
const res = add(1,2,3,4);

curry调用的写法:

function curry(fn,...args){
  const len = fn.length; //fn.length 是函数的参数个数
  const argsArr = [...args];//新建一个数组来保存参数
  return function insideFn(...args){
    argsArr.push(...args) //再次调用继续保存参数
    if(argsArr.length >= len){ //参数收集够了直接执行函数返回结果
      return fn(...argsArr);
    }else{ //否则继续返回函数
      return insideFn;
    }
  }
}
//调用:
//这样
const res = curry(add)(1,2,3,4);
//或者这样
const res = curry(add)(1)(2)(3)(4);

这时候你可能一脑袋问号?????? 这写法有什么卵用吗? 我直接调用不香吗?

说一说curry的好处:

//我们可以这样使用curry
const curryFn = curry(add,1,2);
const res = curryFn(3,4);
const res1 = curryFn(4,5);
//以后每次调用都不用再传前2个参数

上面curry示例就把参数1和2缓存起来了,试想一下如果参数不是普通类型而是对象或者数组,并且你又对它做了一些处理,那这样只在调用curry的时候处理一次就好,而后续每次再调用curryFn都不会再去处理一遍了。

最后

上面所有的代码都没有做类型判断,如typeof === 'function',理解和会用就好,实际使用可以自己加一下,我就偷个懒,哈哈~


做人和写代码我都不太喜欢复杂的东西,总想着能不能简单点。