天天看點

反思JavaScript:論for循環的死亡

我們一直在使用javascript的for循環。但現在,在最新的函數式程式設計技巧的支援下,過時的它應該退休了。幸運的是,你不必是一個函數式程式設計大師,也可以做出這個改變。更幸運的是,這就是你在眼前項目中可以立馬做的事情!

反思JavaScript:論for循環的死亡

我們一直在使用javascript的for循環。但現在,在最新的函數式程式設計技巧的支援下,過時的它應該退休了。

幸運的是,你不必是一個函數式程式設計大師,也可以做出這個改變。更幸運的是,這就是你在眼前項目中可以立馬做的事情!

那到底javascript的for循環有什麼問題?

for循環設計本身鼓勵改變狀态以及産生副作用,這兩者都是導緻錯誤和不可預知代碼的隐患。

我們都知道全局狀态是糟糕的,應該避免。可是,局部狀态和全局狀态一樣糟糕,隻是因為局部狀态處于一個較小的尺度中,沒有引起注意。是以,我們從來沒有真正解決問題,而是盡量把問題最小化。

對于可變的狀态,在一些未知的時間點,變量會因為某些未知的原因而改變。這時,你要花上數小時進行調試,尋找這個值改變的原因。光為這,我都不知道自己掉了多少把頭發了。

下面,我想簡單談談副作用。這個詞聽起來就煩人,副作用……媽蛋!難道你會希望自己的程式有什麼副作用?當然不!

但什麼是副作用?

當一個函數修改了其作用域以外的某些東西時,它就被視為有副作用。可以是改變一個變量的值、讀取鍵盤輸入、調用某個api、寫入磁盤資料、列印日志,等等。

副作用很強大,但同時也被承擔着重大的責任。

副作用應該盡可能被消除,或者封裝在内部,或可控。有副作用的函數難以測試,也難以推斷,是以要盡你所能甩掉它。幸好這裡可以不用擔心副作用。

好了,閑話少說,上代碼。我們看一下這段或許你已經看過上千次典型的for循環:

const cats = [ 

  { name: 'mojo',    months: 84 }, 

  { name: 'mao-mao', months: 34 }, 

  { name: 'waffles', months: 4 }, 

  { name: 'pickles', months: 6 } 

var kittens = [] 

// 典型的拙劣寫法:for循環 

for (var i = 0; i < cats.length; i++) { 

  if (cats[i].months < 7) { 

    kittens.push(cats[i].name) 

  } 

console.log(kittens) 

我計劃将這些代碼一步一步重構,讓你清楚地看到将這些代碼轉換成更漂亮的寫法是多麼容易。

第一個改變就是把if裡的聲明抽象為一個函數:

const iskitten = cat => cat.months < 7 

  if (iskitten(cats[i])) { 

通常,抽出if語句是個不錯的做法。過濾的着眼點從“小于7個月”轉變為“是一隻小貓”非常非常重要。現在,當你再看這段代碼,意圖就變得清晰了。為什麼要取得小于7個月的貓?一點都不明确。我們的意圖是找到小貓,是以讓代碼表示出來!

另一個好處是iskitten現在可複用了,而且我們都明白:

讓代碼可複用應該始終是我們的目标之一。

下一個改變就是提取出從對象貓到貓名字的轉換(或者映射)。這個變化對以後更有意義,現在隻要相信我就好了:

const getname = cat => cat.name 

    kittens.push(getname(cats[i])) 

我本打算先介紹一下filter和map的,但轉念一想,還是直接展示引入它們之後的代碼多好了解,更能讓你體會到代碼可讀性的巨大變化:

const kittens = 

  cats.filter(iskitten) 

      .map(getname) 

還要注意,我們已經消除了 kittens.push(...)。不再有可變的狀态,也不再有var!

使用const的代碼有如魔鬼般性感(超過了var和let)。

這裡說明下,我們自始至終都可以使用const,因為const并不會使對象本身不可變(這個咱們下次再說)。别急,這裡隻是在講一個範例,是以先放我一馬!

重構的最後一步就是把過濾和映射方法也提取到一個函數裡(為了複用嘛,你懂的):

整合一起就是這樣:

const getkittennames = cats => 

const kittens = getkittennames(cats) 

你會如何進一步分解這些函數?仔細想想“小于”或者name屬性、map或filter,說不定能有額外的收獲。你還可以研究下函數的複合,收益更大。

作者:camiler

來源:51cto

繼續閱讀