[图片上传失败...(image-dc4ef6-1581321611007)]
少侠们好~
上次和大家分享了一个关于降低遍历数组时所耗能量的技巧。
通过这个技巧,我们把一开始的代码:
变成了下面这样:
而且在最后,我说了这次会给大家分享一个新的武器,也就是下面这个东西:
这个东西可不好弄,费了挺大劲,不过还好,最后总算给弄来了,
那么,
有的少侠可能要问了:
“天辰,既然这样,你费这么劲弄来的这个武器到底有啥用?”
少侠!
既然你诚心诚意的发问了,
我就大发慈悲的告诉你!
为了防止世界被破坏,
为了维护世界的和平,
贯彻爱与真实的邪恶,
潇洒又迷人的反派角色
天辰……dreamer……
“喂,天辰,你是不是走错片场了?!!!”
“。。。。。。。。”
重新回到刚才的问题来,
这里正确答案应该可能是:
1、上面最后的代码虽然降低了遍历次数,但是,逻辑比较耦合,不利于扩展,transduce就是为了解决这个问题,在保持性能的前提下,也有比较好的扩展性。
2、transducer依赖了很多关键知识点,学习transducer能够帮助少侠你更好的理解它们。
3、学习transducer能够很好的锻炼抽象思维,帮助少侠们打开脑洞。
、能够用来装逼~
好了,
现在开始进入正题~
为了理解transduce, 我们首先需要理解reduce,
我们先来回顾一下上次最后时刻的代码:
在最后,我们只用一个reduce函数,就实现了过滤,映射,以及最后的叠加操作。
少侠你应该也发现了,
reduce函数比我们想象中的更厉害,
那么,
既然reduce函数这么强大,我们能不能用它来代替map或者filter函数呢?
对于这个问题,
有的少侠可能会说了,
“切~,既然天辰你都这么问了,那答案肯定是能啊,要不然你问它干嘛?”
对于这类少侠,天辰想说的是:
“就TM你话多!~”
但是~
我们确实可以用reduce实现map和filter一样的效果。
还是从简单的例子开始:
这有一个数组:
用map翻倍nums中的数字:
用filter过滤掉nums中的奇数:
是不是觉得很简单?
那么我们如何使用reduce实现相同的效果呢?
也很简单!
少侠请看~
使用reduce翻倍nums里面数字:
使用reduce过滤nums中的奇数:
怎么样!很简单吧?
翻倍数字了吧?
过滤出奇数了吧?
到这里,少侠你心里肯定在想:
哈哈,少侠你先别激动!
虽然上面两个例子是有点过分~
但是!
(这里请自动切换成严肃脸~)
通过上面2个例子,我们至少明白了一件事,
那就是reduce是能够给我们想要的结果的,
它既可以像map那样,对一些元素执行操作,然后给我们一个相同长度的数组;
也可以像filter一样,给我们一个过滤掉某些元素后的比较短的数组;
或者其他一些奇奇怪怪的东西~
那么,
接下来我们的问题就是,
如何让reduce返回给我们想要的东西呢?
这里少侠你可能有2种情况,
第一种就是,你已经知道了你想要的结果,然后你直接通过reduce最后返回这个结果,也就是上面两个例子。。。
换句话说,reduce实际上啥也没做,只不过进去兜了一圈。。。
“reduce老弟,天辰那家伙又来翻倍nums数组了,上次是什么结果你还记得不?”
“记得,是 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]”
“好,直接扔给它,我们出去玩去~”
“嗯,好~”
当然,如果少侠你没有我天辰这么优秀~
你很可能没办法在一开始就知道具体的结果是什么,
这个时候,你就得自己告诉reduce如何生成你想要的元素了,
比如这样:
换个简单些的写法,同时把reduce里面的函数放到外面来:
好了,少侠~
我们已经初步实现了map的效果,那么接下来就应该是filter了,
一样的思路:
现在filter也有了,
我们把两种reducer结合起来使用一遍:
完全OK~
到这里,有的少侠可能就要说了:
“住手!天辰,你这样的话,你不是又要遍历2次数组,上次装逼时怎么说的你自己都忘了?!”
好吧,少侠,你还算是一个比较细心的人,
这里我们用了两次reduce, 所以确实会遍历2次数组,
但是~
谁说我就一定得用2次reduce了?
看好了,
少侠~
接下来我要开始装逼了,
基础内力不深厚的少侠请主动退后10米站远一些!
首先,
我们已经把mapReducer里面的翻倍操作提取出来了,
也就是我们熟悉的double函数,
现在,我们试着把mapReducer里面的向数组添加值的这个操作,
也单独提取出来:
然后,按照我们上一章说的,
mapReducer现在会严重依赖当前作用域中的double函数和pushValue函数,
所以,我们给它换种方式,换成通过传参的形式获取:
注意,少侠~
这里看着可能稍微复杂了一些,
但是所有我们做的,
实际上就只是把原先直接通过作用域访问的函数,
换成了依次通过函数参数传递访问而已,
把函数改成通过参数传递之后,
我们每次就可以自由选择传递什么函数进去,
比如,把double函数换成add1:
根据这个思路,
改变后的filterReducer会是这样:
到这里,如果少侠你有点懵逼的话。。。
别急,
待会儿你可能会更懵逼的!
以后有机会我们会回头单独分析里面的知识点的。。。
这里的重点是,现在我们可以更灵活的使用reduce了:
我知道你们想说什么~
现在还是用了2次reduce。。。
少侠你看,我现在在最后传递的是pushValue作为joinFn函数,
也就是说,过滤出奇数后,就添加到数组当中,
但是,我也可以,在添加到数组当中之前,不马上添加到数组中,
我们先翻倍一下过滤出的奇数,
完了过后再添加到数组当中~
现在只有一次reduce了!
然后,
不知道少侠你有没有注意到,
magic函数实际上可以用mapReducer函数实现
(请仔细认真观察~)
替换掉magic:
好了,
装逼结束~
哈哈哈哈哈哈!
“喂,天辰!你在这儿吹什么牛逼呢,你是不是忘了什么东西?说好的transduce呢!!!”
哦,差点忘了。。。
好吧,少侠,
transduce就是对下面这部分代码的进一步抽象:
但是,
老实说,
解释transduce比我想象的还要麻烦。。。
(早知道就该不选这个东西。。。。)
首先,
transduce通常需要一个compose函数配合使用:
有了compose函数,我们就可以简化下面的代码:
然后,
transduce大概长这个样子:
里面的参数分别对应下面几个部分:
其实就是把开始的几个部分拆分了开来,
这是它的使用方式,
把所有代码结合起来:
如果我们想增加一条过滤条件:
或者如果我们最后不是想获得数组,
而是给数组里面的数字求和的话:
好了,
恭喜你,少侠!
你又成功发现并阅读完了一篇文章~
按照惯例,首先~
谢谢少侠你看到了这里,
然后~
有的少侠可能会对这篇文章觉得比较懵逼,
这很正常,
一是少侠我可能写得也不是很清楚,
还有就是transduce的实现确实涉及到了很多其他的知识,
一大堆高阶函数,函数闭包,偏函数应用,以及函数组合compose等,
那么我为什么要把transduce分享给大家呢?
因为,
transduce本身也许并不是很重要,
少侠你完全可以不使用它,
但是,理解和掌握它所需的知识,对很多少侠来说都很重要,
特别是对想追求卓越,当一个dreamer的少侠~
还有就是。。。
如果少侠你平时对高阶函数,闭包,this关键字这些东西都比较懵逼的话,
比较抗拒的话~
那么,先看看更懵逼的东西,
等回过头再来看它们,
你会觉得它们亲切多了~
所以~
少侠,
你到底懵逼了没?
一些你可能关心的问题:
1、天辰,你老实说!你写这篇文章是不是就是想装逼?
少侠,装逼能帮我吸引到妹子不?
如果能,那我就是在装逼,
如果不能,那我就是在分享技术文章。。。
2、天辰,这次你弄了个感觉没什么用的transduce,下次又打算弄什么东西来?
这次不能随便立flag了,
弄个transduce差点把我坑死。。。
不过,
下次可能会遇见下面几种情况之一,
遇见一个新的道具,比如上面遇见的compose函数:
遇见新的秘籍或残卷,关于函数,对象,递归什么的:
遇见一个冒险挑战,完成某个特殊的挑战:
3、天辰,你说transduce设计到了很多关键知识点。。。
哈哈哈哈哈~
其他资源:
文章:
Transducers: Efficient Data Processing Pipelines in JavaScript
Understanding Transducers in JavaScript
工具库:
ramda库中的transduce
transducer.js
好了,
少侠,江湖路上,有缘再见~