少俠們好~數組
今天和你們分享一篇關於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)大陸獲取到的,可以更酷(更裝逼)地處理咱們今天遇到的問題,
雖然可能須要少俠你有必定的修爲才能使用,
可是~
無論怎樣,我相信少俠你最終確定能掌握它。
一些你可能關心的問題:
一、天辰,你說的這些,能幫助我漲工資嗎?
說能的話顯得有點裝逼!可是,少俠若是你能像這樣堅持不斷學習的話,相信你之後不只能漲工資,還能給別人發工資!
二、天辰,我不關心工資,我關心的是,瞭解這些能幫助我找到女友嗎?
看見這個狗頭了沒?🐶
我要有找女友的方法我還會在這寫技術文章?!
固然,不排除某些優秀的少俠能在開發妹子面前用技術裝逼從而吸引到妹子。。。
三、還有!天辰你的代碼爲何要放圖片,而不是直接貼文字代碼呢?我都不能複製粘貼測試。
第一,放圖片應該要好看些。
第二,不能複製代碼就對了!少俠你應該本身動手敲一遍代碼,這樣印象才比較深入,請養成本身動手的好習慣!
好了,
少俠,江湖路上,有緣再見~