如何優雅地改善程序中for循環

如何優雅地改善程序中for循環.title

衆所周知,在咱們的平常編碼裏,對於一些數據的迭代以及遍歷,首先想到的是for循環html

這沒毛病,for循環編寫語法很簡單,只須要知道數據列表的長度便可進行遍歷取值,舉個例子:前端

for循環

有點編程基礎的童鞋,均可以很快想到上面的編寫方法。那不知道你們是否會跟我同樣對於寫for循環時,功能是沒毛病,但編寫起來總會以爲很不優雅,例如還要定義對應的i變量(拿上述舉例)以及還要自主控制i變量的變化,這樣無疑會變得繁瑣起來,也會讓咱們編寫代碼效率有所降低面試

好了,那咱們有沒有一些優雅的方法處理上述案例呢?答案是確定的,這就回到這篇文章的主題:如何優雅地改善for循環編程

ForEach

相信學過ES6的童鞋,很快就會想到這種方法,下面我就拿上面的例子改造一下:後端

forEach遍歷

這種方式,看起來優雅了許多,省去了沒必要要的隊列長度對比變量的定義和控制以及隊列長度判斷api

到這裏,ForEach是否是就是最好的優雅方案?有沒有存在問題?,相信一部分童鞋未必能答出來,那我就不賣關子了。若是咱們遇到一種狀況,就是對列表遍歷處理後,須要返回一個處理後的數組,那咱們繼續使用forEach是否可以達到咱們的目的呢?咱們也許會有如下作法:數組

forEach全局污染

能夠看到,第一種處理是但願處理完後直接賦值給一個變量,然而forEach循環返回的是undefined,第二種處理雖然最終的確可以達到咱們目標,拿處處理完的數據,卻致使了一個問題--全局變量的污染。固然也能夠在外部定一個數組,而後push處理後的數據到新數組來實現咱們的目標,但總體看起來依然不是很優雅。函數

那有木有一種方法可以返回一個新數組,而且又不會影響到原來的數據呢?答案是確定的,這就要提到強大的Functional Programing(簡稱FP)編碼

Functional Programing

FP是什麼?又是用來幹什麼的?spa

Functional programmings(FP) means coding in functions

這是比較簡潔和官方的說法,那是什麼意思?簡單地說,就是,用函數的方式處理問題,今天就會用到它的其中一個核心思想:純函數(對於相同的輸入,永遠獲得相同的輸出,並且不會有任何的反作用)

看到這裏是否是有點頭緒了😄,好啦,回到正題,那在js裏面有那些方法是純函數,並且又能優雅地替代for循環?相信童鞋們都會想到了map()

Map()

Map方法會對原始數組中的每一個元素進行遍歷一次,並調用callback,最終返回一個新的數組而不會影響到原始數組。

咱們如今就拿上述forEach存在問題的栗子進行改造一下:

Map循環

好明顯,曾經的多行循環代碼只須要一行就能夠完成,看着也優雅了好多,並且返回一個新的處理後的素組以及不會對原有的數組產生污染

Filter()

Filter方法,簡單滴說就是對數組進行篩選或過濾,而後返回一個新的數組,並不會對原始數組產生任何的影響

看到這裏,咱們又要回到for循環那個栗子,使用Filter方法是否可讓代碼優雅起來?如今就來動手看看:

filter循環

明顯,使用Filter方法只能達到了第一步目標就是優雅了for循環裏的條件語句,那該怎麼辦?

咱們會發現,Filter方法是會返回一個新數組,那咱們就能夠聯繫到了Map方法,二者結合會產生什麼火花?

filter與map結合

至此,是否會以爲看起來舒服好多,並且也通俗易懂,而這也是最終優雅方案。那麼問題來了,何時該用forEach,何時又該用map呢?

forEach比較適用於不改變原始數組數據,僅僅拿數組數據進行作一些事情,而map則適用於改變數據值而且返回一個新數組,固然不一樣情景又不一樣的作法,這僅僅只是做爲一個參考

Extension

除了上述提到的經常使用情景外,咱們還會遇到不少其餘地方能夠繼續優雅for循環,這就不得不提some方法和every方法以及reduce方法(reduce也屬於FP)

  1. Every()和Some()

    如今有一種情景,就是要根據後端返回的一個列表裏費用低於0時就展現提示語。結合上述學過的方法,也許咱們會有如下作法:

    for循環

    除了上述比較的直接方法外,也許有些童鞋會想到直接使用forEach來進行優雅一下:

    forEach循環

    由於forEach處理數據是在callback上,所以使用break語法明顯會致使語法錯誤,所以,就算去掉break,也須要遍歷完全部元素,而主角來了,some和every:

    • some:遍歷數組元素,只要遇到條件爲true則直接返回true,不然直到遍歷最後並返回false
    • every:遍歷數組元素,只要遇到條件爲false則直接返回false,不然直到遍歷最後並返回true

some和every

明顯看着代碼量就簡潔了好多,並且也不失優雅。
  1. reduce()

    可能有些童鞋對於reduce方法有點陌生,它到底是用來幹嗎的?應用場景又是什麼?

    reduce() 方法接收一個函數做爲累加器(accumulator),數組中的每一個值(從左到右)開始縮減,最終爲一個值

    上面爲官方的說法,簡單地理解,就是對一個列表進行遍歷,第一次取兩個元素進行處理獲得一個新值,而後到下一次循環時就拿該新值與第三個元素進行處理,以此類推,最終獲得一個值並返回。文字太複雜,直接圖解:

    reduce解析

    是否是清晰不少了,那應用的優雅情景又有哪些?在這裏我就不賣關子了,例如,後端返回一個對象,而咱們須要對這個對象進行處理只須要獲得指定屬性值,多餘的屬性就過濾掉。平常作法:

    對象遍歷

    能夠看到,雙層循環讓人看起來的確複雜不少,並且稍微不當心就會很容易出問題。然而使用reduce方法就能夠優雅起來。

    reduce遍歷

    看了這個,是否是以爲reduce用了後特別簡潔和優雅。

    若是你以爲它還不夠強大,再看看下面一個栗子,就能夠以爲它的厲害(這是額外話題了,你們有空能夠研究一下)。咱們常常會遇到一種狀況就是,後端返回一個嵌套很深的對象,而後前端拿到這個複雜的對象中某個屬性時,不免會須要每個值都要判斷是否存在,而後直到指定的屬性爲止,這就是鏈式取值問題:

    鏈式取值最死板方法

    其實鏈式取值問題在網上有不少處理方案,那若是是最優雅方案,我以爲就是使用reduce,那麼使用reduce怎麼編寫呢?直接上圖

    reduce鏈式取值

    至此,對於for循環的優雅性,不一樣場景能夠有不少的優雅方案(lodash等等),但我想說的是,原生js自己提供的api其實有不少方法是可讓咱們的程序變得便捷以及簡潔的,只有你多點用用它,就會體會到它的強大。哈哈,若是上文若是有不妥之處,歡迎各位大佬指點一下

Last

最後,看完上文,相信你們對for循環有必定的認識了(我猜的),那就用一道常見的面試題做爲結尾來讓你們回去思考一下用什麼方法最好吧:

實現一個方法,計算出一個字符串中每一個字符出現的次數?

方法我就不寫了,讓你們來一場頭腦風暴吧🙈

相關文章
相關標籤/搜索