少侠们好~数组
今天和你们分享一篇关于JS数组里面的map,filter,reduce相关函数的知识,闭包
相信少侠们确定或多或少都了解过一些相关知识,特别对于map和filter这种很经常使用的函数的用法,可能已经信手拈来了,ide
可是~函数
少侠,学习
你真的肯定,你目前所使用的方式,就是它们的正确使用姿式吗?测试
若是想知道所做的选择是否明智,就看你在清楚知道将会付出什么代价的状况下,是否依然选择那样作。优化
————《黑客帝国3》3d
首先,让咱们从最一个比较简单的例子开始:cdn
这里有一个从1到10的数组:blog
如今,若是少侠你须要取出中间的奇数,你会怎么作呢?
这个问题不难,有的少侠可能会使用for循环来过滤出偶数,某些少侠可能会使用while循环,又或是使用数组自带的filter方法。
这里,咱们先不考虑使用for和while这些迭代方法,咱们选择使用数组自带的filter方法,若是使用filter方法的话,
少侠你的代码大概可能会是这样的:
仍是挺简单的对吧?
相信大部分少侠都能很轻松完成。
在filter函数内部,咱们使用 num % 2 !== 0 来判断 是不是一个奇数,若是是一个奇数,就过滤出来。
在这里,有的少侠可能就会想到,若是把这个判断过程单独分红一个函数,会方便一些,也方便之后的修改扩展。
好比,单独写成一个 isOdd函数:
而后在filter里面使用这个函数,是吧?
可是!
一些少侠这里就会开始犯一个天真的错误了,
你可能会写成下面这样:
看见这样的代码,有的少侠可能会说,天辰,这样写没有什么问题啊,我也测试过了,结果都是正确的,怎么就天真了?
没错,结果是正确的,
可是,你每次在filter里面都额外调用了一次并不必定须要的函数。
也就是包裹着 return isOdd(num)的那个外层箭头函数。
若是你还没看出来问题的话,先看看这个例子:
这里的sayHello接受一个字符串name, 而后返回 'hello' + name.
helpSayHello一样接受一个字符串name,而后用这个name 调用 sayHello, 获得返回的 'hello' + name.
那么,少侠你看看,下面两句代码结果有什么区别呢?
咱们干吗不直接调用sayHello呢?
“这样啊,大概理解了,可是天辰你告诉我,鸽子为何那么大? 到底哪里调用了2次了?”
“。。。。。。”
好吧,那换个角度,
如今发现了没?
filter里面那个函数是否是和isOdd如出一辙?
因此,咱们直接把isOdd放进去就能够了:
“道理我懂了,可是谁能告诉我,鸽子到底为何那么大? 为何以前那样会多调用一次函数?”
“。。。。。。。算了,接着看下面的内容吧”
若是要把nums里面的数字翻倍,用map函数,又该怎么作呢?
聪明的少侠此次确定一下就明白了:
好了,既然如今咱们知道了如何从nums数组里面过滤出奇数,如何翻倍里面的数字,那么,接下来咱们就更进一步:
从nums里面过滤出全部奇数,并翻倍这些奇数。
这个问题也不难是吧?
让我猜一下,一些少侠应该会写成下面这样:
若是咱们还想继续算出全部奇数翻倍后的和的话:
嗯,一个串一个看起来很酷是吧? 最后的结果也是正确的。
可是。。。
少侠你依然比较天真!
这样串起来的后果就是,咱们会遍历3次数组,filter的时候遍历一次,map的时候遍历一次,reduce的时候再遍历一次。
如今数组只有10个数字,影响还不大,可是若是是很大的数组,好比100万个数字,遍历3遍的话,那么就会多访问150万次,
150万次什么概念?
少侠你有150万存款嘛?
因此,这种方式其实不算是一种很好的方式,
到这里有的少侠可能要问了,若是这种方式不是很好,有什么更好的方式呢? 我要怎么去找到更好的方式呢?
实际上,
要找到更好的方式,这里咱们首先能够尝试的是
凭感受。。。。
想象一下,若是让你本身从中间取出全部奇数,翻倍,并求和,你会以为怎么作简单一些呢?
是否是以为下面这样才比较正常?
首先,从第一个数字开始,若是它是奇数,就拿出来,翻倍,而后找个地方放起来,
接着,
继续看第二个数字,若是是偶数,就跳过,若是是奇数,就拿出来,翻倍,而后和开始的翻倍后的奇数加起来,找个地方放起来。
接着看第三个数字,以此类推,只要是奇数,就翻倍,而后和以前的结果加起来。
直到咱们找寻到最后一个数字,就能够算出最终结果了,
对吧?咱们并不须要再回头看了。
因此,这样才是正确的方式。
若是使用迭代的话,就是下面这样:
没错,一般这样才是正常的操做。
可是,
这样的代码不太方便,
少侠你确定也不想每次都写这么一大堆for循环语句吧?
因此,咱们能够先试着继续优化一下。
咱们首先试着用一个叫作magic(魔法)的函数把这些步骤包裹起来:
如今看起来好多了,不过,magic内部的操做看起来不是很清晰,
其余少侠看见了可能很难一眼就明白magic函数在作什么,
咱们能够试着把里面的一些步骤分红更小的函数:
去掉注释,换个稍微简洁点的写法:
如今比较简洁也比较清晰了,不过,假如咱们如今要计算是偶数而不是奇数怎么办呢?
或者若是更复杂些,若是是偶数,就反过来,除以二,而后求和,又该怎么办呢?
难道咱们又要复制一次magic函数,而后改动for循环里面的逻辑吗?
也许,咱们能够把for循环内部的逻辑单独提取成一个外部函数!
可是,
少侠们注意了!
这里的问题是,在内部的时候,for能够经过闭包规则,访问到array, 访问到array[i],以及sum,
而当咱们把magicFriend函数放在外面以后,它没办法再访问到magic内部的array, array[i],以及sum了,
由于以前全部逻辑都在magic函数内部,能够经过闭包规则访问到所需变量,如今不行了。
那么怎么解决呢?
很简单~
这里咱们真正关心的是,如何经过其余方式获取到以前经过闭包获取到的参数。
既然闭包的规则没办法帮助咱们获取到所需参数,咱们就换一个能帮咱们获取到对应参数的规则,这里咱们就换成经过函数参数来获取:
固然,如今在magic内部,for循环里面严重依赖当前做用域中一个叫作magicFriend的函数,若是当前做用域中的magicFriend函数不见了,magic函数就没办法正常运行了,
为了更灵活,咱们能够把magicFriend也换成经过参数传递给magic。
等一等!
还有个问题。。。
万一咱们但愿sum从100开始相加呢?
算了,那就把sum也提取出来,经过参数传进去吧。。。
到这里了,有些少侠可能要问了!
天辰你到底有完没完了?
整这些花里胡哨的有什么用?
别急! 少侠~ 接下来就是见证奇迹的时刻!
首先,咱们给代码里面部分函数和参数改一下名字:
是否是有点眼熟了? 接着,咱们换成数组自带的reduce函数:
最后回到咱们上面的问题:
彻底OK!
此次咱们用reduce只遍历了一次数组就完成了以前的操做!
如今知道为何以前要把reduce叫作magic(魔法)了吧!
不过~~
到这里, 有的少侠可能会以为有点奇怪,那么以前的filter和map呢? 为何如今就不须要它们了呢?
针对这个问题,天辰个人答案是:
由于咱们根本就不是在单纯地执行map或filter操做~
若是少侠你真的只是单纯地想把一堆数据,映射成另外一对数据,才是用map。
若是少侠你真的只是单纯地想过滤出一些数据,才是用filter。
除此以外,若是你既要过滤(filter)一些东西,同时又要映射(map)一些东西,
那么,少侠你实际上既不是在作map操做,也不是作filter操做,这个时候,请考虑采用reduce(magic)!
不行! 说好了只使用map,多一个filter,多一个map,都不算map!
好了,
恭喜你,少侠!
你成功发现并阅读完了这篇文章~
首先~
谢谢少侠你看到了这里,
而后~
无论少侠你如今处于什么阶段,但愿你都能从中有所收获。
那么如今要结束了?
固然不行!
无论大家下次还有没有兴趣,按照惯例,在结束以前必须留个悬念吊一下胃口~
因此,提早预告一下下期内容。。。
下一次,天辰会和少侠们分享一个有趣的武器,
这个武器是天辰费了很大劲从救赎(JS)大陆获取到的,可以更酷(更装逼)地处理咱们今天遇到的问题,
虽然可能须要少侠你有必定的修为才能使用,
可是~
无论怎样,我相信少侠你最终确定能掌握它。
一些你可能关心的问题:
一、天辰,你说的这些,能帮助我涨工资吗?
说能的话显得有点装逼!可是,少侠若是你能像这样坚持不断学习的话,相信你之后不只能涨工资,还能给别人发工资!
二、天辰,我不关心工资,我关心的是,了解这些能帮助我找到女友吗?
看见这个狗头了没?🐶
我要有找女友的方法我还会在这写技术文章?!
固然,不排除某些优秀的少侠能在开发妹子面前用技术装逼从而吸引到妹子。。。
三、还有!天辰你的代码为何要放图片,而不是直接贴文字代码呢?我都不能复制粘贴测试。
第一,放图片应该要好看些。
第二,不能复制代码就对了!少侠你应该本身动手敲一遍代码,这样印象才比较深入,请养成本身动手的好习惯!
好了,
少侠,江湖路上,有缘再见~