compose是不是可以这样理解

1,862 阅读2分钟

前言

写这篇文章的目的是让我更好的理解它,我很早就看过compose的实现,但时不时得忘记,特别的是 reducer下的实现,那肯定应该是我理解有问题,今天看ssh大佬的群里也有讨论;决定重新再理解一遍,有了自己的想法,赶脚写一下。(有不对的地方,请多多指点) 

compose实现了什么

(...args) => f1(f2(f3(f4(...arg)))) // 1 -> n

思考一下compose的雏形

(...args) => f1(f2(...args))  //我觉得是这样的, 😄

👆这个🌰实现了的是一个函数,入参是...args,执行了f1函数,入参是f2(...args)

(记住上面句话哦!!!)

发现这个函数模型的前生

这位大佬心路历程应该是这样的(纯属虚构)

有一天大佬,想实现一个函数,入参是...args,执行了f1函数,入参是f2(...args)

(...args) => f1(f2(...args))

想再加个f3, 试试?

(...args) => f1(f2(f3(...args)))

心想有点意思😯,再来一个

(...args) => f1(f2(f3(f4(...args))))

他开始想是n个函数怎么搞呢,难啊😣

是不是有规律呢?

(...args) => f1(f2(...args))
(...args) => f1(f2(f3(...args)))  
(...args) => f1(f2(f3(f4(...args))))
(...args) => f1(f2(f3(f4(f5(...args))))))

聪明的大佬🧍‍♂️发现

(...args) => f1(f2(f3(...args)))

这个是不是可以这样理解

实现了一个函数入参是...args,执行了_f函数入参是f3(...args)

那_f是什么呢?应该是个函数,而且内部执行了f1(f2()),这...不是他嘛😄

(...args) => f1(f2(...args))

那下面是不是也这样呢?

(...args) => f1(f2(f3(f4(...args))))   //(...args) => _f(f4(...args)) 
(...args) => f1(f2(f3(...args)))       //_f函数 

哇好神奇啊

不就这样嘛,🍳

let cache = (...args) => f1(f2(...args))
cache = (...args) => cache(f3(...args))

完整实现一下

按照自己思路,笨笨的实现一下😄

let cache;

function compose(...fns) {
  let ff = fns[0]
  for (let i = 1; i < fns.length; i ++) {
    if (cache) {
      cache = (...args) => cache(fns[i](...args));
    } else {
      cache = (...args) => ff(fns[i](...args));
    }
  }
  return cache;  
}

大神的实现

const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));

再来理解一下,仔细一看,这个f不是就是我上面的cache嘛,大佬就是不一样,实现得如此优雅

回顾一下reduce的实现吧

//简化版 仅供参考
Array.prototype.myReduce = function (fn, p) {
  let that = this;
  p = p || that[0];
  for (let i = 1; i < that.length; i++) {
     p = fn(p, that[i]);
  }
  return p;
}

总结

一些高阶函数,感觉都是由简到繁的抽象,代码的重构亦是如此

这个理解方式对我蛮好理解的,希望对你帮助