少俠留步! 你可能一直都誤解了map,filter和reduce.

image

少俠們好~

今天和大家分享一篇關(guān)于JS數(shù)組里面的map,filter,reduce相關(guān)函數(shù)的知識,

相信少俠們肯定或多或少都了解過一些相關(guān)知識,特別對于map和filter這種很常用的函數(shù)的用法,可能已經(jīng)信手拈來了,

但是~

少俠,

你真的確定,你目前所使用的方式,就是它們的正確使用姿勢嗎?

如果想知道所作的選擇是否明智,就看你在清楚知道將會付出什么代價的情況下,是否依然選擇那樣做。

————《黑客帝國3》


首先,讓我們從最一個比較簡單的例子開始:

這里有一個從1到10的數(shù)組:

image

現(xiàn)在,如果少俠你需要取出中間的奇數(shù),你會怎么做呢?

這個問題不難,有的少俠可能會使用for循環(huán)來過濾出偶數(shù),某些少俠可能會使用while循環(huán),又或是使用數(shù)組自帶的filter方法。

這里,我們先不考慮使用for和while這些迭代方法,我們選擇使用數(shù)組自帶的filter方法,如果使用filter方法的話,

少俠你的代碼大概可能會是這樣的:

image

還是挺簡單的對吧?

相信大部分少俠都能很輕松完成。

在filter函數(shù)內(nèi)部,我們使用 num % 2 !== 0 來判斷 是否是一個奇數(shù),如果是一個奇數(shù),就過濾出來。

在這里,有的少俠可能就會想到,如果把這個判斷過程單獨(dú)分成一個函數(shù),會方便一些,也方便以后的修改擴(kuò)展。

比如,單獨(dú)寫成一個 isOdd函數(shù):

image

然后在filter里面使用這個函數(shù),是吧?

但是!

一些少俠這里就會開始犯一個天真的錯誤了,

你可能會寫成下面這樣:

image

看見這樣的代碼,有的少俠可能會說,天辰,這樣寫沒有什么問題啊,我也測試過了,結(jié)果都是正確的,怎么就天真了?

沒錯,結(jié)果是正確的,

但是,你每次在filter里面都額外調(diào)用了一次并不一定需要的函數(shù)。

也就是包裹著 return isOdd(num)的那個外層箭頭函數(shù)。

image

如果你還沒看出來問題的話,先看看這個例子:

image

這里的sayHello接受一個字符串name, 然后返回 'hello' + name.

helpSayHello同樣接受一個字符串name,然后用這個name 調(diào)用 sayHello, 得到返回的 'hello' + name.

那么,少俠你看看,下面兩句代碼結(jié)果有什么區(qū)別呢?

我們干嘛不直接調(diào)用sayHello呢?

image

“這樣啊,大概理解了,但是天辰你告訴我,鴿子為什么那么大? 到底哪里調(diào)用了2次了?”

(不知道鴿子為什么那么大什么意思的點(diǎn)擊這里查看~)

image

“。。。。。。”

好吧,那換個角度,

image

現(xiàn)在發(fā)現(xiàn)了沒?

filter里面那個函數(shù)是不是和isOdd一模一樣?

所以,我們直接把isOdd放進(jìn)去就可以了:

image

“道理我懂了,但是誰能告訴我,鴿子到底為什么那么大? 為什么之前那樣會多調(diào)用一次函數(shù)?”

“。。。。。。。算了,接著看下面的內(nèi)容吧”

如果要把nums里面的數(shù)字翻倍,用map函數(shù),又該怎么做呢?

聰明的少俠這次肯定一下就明白了:

image

好了,既然現(xiàn)在我們知道了如何從nums數(shù)組里面過濾出奇數(shù),如何翻倍里面的數(shù)字,那么,接下來我們就更進(jìn)一步:

從nums里面過濾出所有奇數(shù),并翻倍這些奇數(shù)。

這個問題也不難是吧?

讓我猜一下,一些少俠應(yīng)該會寫成下面這樣:

image

如果我們還想繼續(xù)算出所有奇數(shù)翻倍后的和的話:

image

嗯,一個串一個看起來很酷是吧? 最后的結(jié)果也是正確的。

但是。。。

少俠你依然比較天真!

這樣串起來的后果就是,我們會遍歷3次數(shù)組,filter的時候遍歷一次,map的時候遍歷一次,reduce的時候再遍歷一次。

現(xiàn)在數(shù)組只有10個數(shù)字,影響還不大,但是如果是很大的數(shù)組,比如100萬個數(shù)字,遍歷3遍的話,那么就會多訪問150萬次,

150萬次什么概念?

少俠你有150萬存款嘛?

更壞的情況會是當(dāng)你習(xí)慣這種方式后,你可能會連接更多的函數(shù)。。。。

array
.map(fn1)
.map(fn2)
.filter(fn4)
.filter(fn5)
.forEach(fn6)
.....

所以,這種方式其實(shí)不算是一種很好的方式,

到這里有的少俠可能要問了,如果這種方式不是很好,有什么更好的方式呢? 我要怎么去找到更好的方式呢?

實(shí)際上,

要找到更好的方式,這里我們首先可以嘗試的是

憑感覺。。。。

想象一下,如果讓你自己從中間取出所有奇數(shù),翻倍,并求和,你會覺得怎么做簡單一些呢?

是不是覺得下面這樣才比較正常?

首先,從第一個數(shù)字開始,如果它是奇數(shù),就拿出來,翻倍,然后找個地方放起來,

接著,

繼續(xù)看第二個數(shù)字,如果是偶數(shù),就跳過,如果是奇數(shù),就拿出來,翻倍,然后和開始的翻倍后的奇數(shù)加起來,找個地方放起來。

接著看第三個數(shù)字,以此類推,只要是奇數(shù),就翻倍,然后和之前的結(jié)果加起來。

直到我們找尋到最后一個數(shù)字,就可以算出最終結(jié)果了,

對吧?我們并不需要再回頭看了。

所以,這樣才是正確的方式。

如果使用迭代的話,就是下面這樣:

image

沒錯,通常這樣才是正常的操作。

但是,

這樣的代碼不太方便,

少俠你肯定也不想每次都寫這么一大堆for循環(huán)語句吧?

所以,我們可以先試著繼續(xù)優(yōu)化一下。

我們首先試著用一個叫做magic(魔法)的函數(shù)把這些步驟包裹起來:

image

現(xiàn)在看起來好多了,不過,magic內(nèi)部的操作看起來不是很清晰,

其他少俠看見了可能很難一眼就明白magic函數(shù)在做什么,

我們可以試著把里面的一些步驟分成更小的函數(shù):

image

去掉注釋,換個稍微簡潔點(diǎn)的寫法:

image

現(xiàn)在比較簡潔也比較清晰了,不過,假如我們現(xiàn)在要計算是偶數(shù)而不是奇數(shù)怎么辦呢?

或者如果更復(fù)雜些,如果是偶數(shù),就反過來,除以二,然后求和,又該怎么辦呢?

難道我們又要復(fù)制一次magic函數(shù),然后改動for循環(huán)里面的邏輯嗎?

也許,我們可以把for循環(huán)內(nèi)部的邏輯單獨(dú)提取成一個外部函數(shù)!

image

但是,

少俠們注意了!

這里的問題是,在內(nèi)部的時候,for可以通過閉包規(guī)則,訪問到array, 訪問到array[i],以及sum,

而當(dāng)我們把magicFriend函數(shù)放在外面之后,它沒辦法再訪問到magic內(nèi)部的array, array[i],以及sum了,

因?yàn)橹八羞壿嫸荚趍agic函數(shù)內(nèi)部,可以通過閉包規(guī)則訪問到所需變量,現(xiàn)在不行了。

那么怎么解決呢?

很簡單~

這里我們真正關(guān)心的是,如何通過其他方式獲取到之前通過閉包獲取到的參數(shù)。

既然閉包的規(guī)則沒辦法幫助我們獲取到所需參數(shù),我們就換一個能幫我們獲取到對應(yīng)參數(shù)的規(guī)則,這里我們就換成通過函數(shù)參數(shù)來獲取:

image

當(dāng)然,現(xiàn)在在magic內(nèi)部,for循環(huán)里面嚴(yán)重依賴當(dāng)前作用域中一個叫做magicFriend的函數(shù),如果當(dāng)前作用域中的magicFriend函數(shù)不見了,magic函數(shù)就沒辦法正常運(yùn)行了,

為了更靈活,我們可以把magicFriend也換成通過參數(shù)傳遞給magic。

image

等一等!

還有個問題。。。

萬一我們希望sum從100開始相加呢?

算了,那就把sum也提取出來,通過參數(shù)傳進(jìn)去吧。。。

image

到這里了,有些少俠可能要問了!

天辰你到底有完沒完了?

整這些花里胡哨的有什么用?

別急! 少俠~ 接下來就是見證奇跡的時刻!

首先,我們給代碼里面部分函數(shù)和參數(shù)改一下名字:

image

是不是有點(diǎn)眼熟了? 接著,我們換成數(shù)組自帶的reduce函數(shù):

image

最后回到我們上面的問題:

image

完全OK!

這次我們用reduce只遍歷了一次數(shù)組就完成了之前的操作!

現(xiàn)在知道為什么之前要把reduce叫做magic(魔法)了吧!

不過~~

到這里, 有的少俠可能會覺得有點(diǎn)奇怪,那么之前的filter和map呢? 為什么現(xiàn)在就不需要它們了呢?

針對這個問題,天辰我的答案是:

因?yàn)槲覀兏揪筒皇窃趩渭兊貓?zhí)行map或filter操作~

如果少俠你真的只是單純地想把一堆數(shù)據(jù),映射成另一對數(shù)據(jù),才是用map。

如果少俠你真的只是單純地想過濾出一些數(shù)據(jù),才是用filter。

除此之外,如果你既要過濾(filter)一些東西,同時又要映射(map)一些東西,

那么,少俠你實(shí)際上既不是在做map操作,也不是做filter操作,這個時候,請考慮采用reduce(magic)!

不行! 說好了只使用map,多一個filter,多一個map,都不算map!

image

好了,

恭喜你,少俠!

你成功發(fā)現(xiàn)并閱讀完了這篇文章~

首先~

謝謝少俠你看到了這里,

然后~

不管少俠你現(xiàn)在處于什么階段,希望你都能從中有所收獲。

那么現(xiàn)在要結(jié)束了?

當(dāng)然不行!

不管你們下次還有沒有興趣,按照慣例,在結(jié)束之前必須留個懸念吊一下胃口~

所以,提前預(yù)告一下下期內(nèi)容。。。

下一次,天辰會和少俠們分享一個有趣的武器,

這個武器是天辰費(fèi)了很大勁從救贖(JS)大陸獲取到的,能夠更酷(更裝逼)地處理我們今天遇到的問題,

雖然可能需要少俠你有一定的修為才能使用,

但是~

不管怎樣,我相信少俠你最終肯定能掌握它。

image

一些你可能關(guān)心的問題:

1、天辰,你說的這些,能幫助我漲工資嗎?

說能的話顯得有點(diǎn)裝逼!但是,少俠如果你能像這樣堅持不斷學(xué)習(xí)的話,相信你以后不僅能漲工資,還能給別人發(fā)工資!

2、天辰,我不關(guān)心工資,我關(guān)心的是,了解這些能幫助我找到女朋友嗎?

看見這個狗頭了沒??

我要有找女朋友的方法我還會在這寫技術(shù)文章?!

當(dāng)然,不排除某些優(yōu)秀的少俠能在開發(fā)妹子面前用技術(shù)裝逼從而吸引到妹子。。。

3、還有!天辰你的代碼為什么要放圖片,而不是直接貼文字代碼呢?我都不能復(fù)制粘貼測試。

第一,放圖片應(yīng)該要好看些。

第二,不能復(fù)制代碼就對了!少俠你應(yīng)該自己動手敲一遍代碼,這樣印象才比較深刻,請養(yǎng)成自己動手的好習(xí)慣!


好了,

少俠,江湖路上,有緣再見~

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容