新聞中心
我們一直在使用JavaScript的for循環(huán)。但現(xiàn)在,在最新的函數(shù)式編程技巧的支持下,過時的它應(yīng)該退休了。幸運的是,你不必是一個函數(shù)式編程大師,也可以做出這個改變。更幸運的是,這就是你在眼前項目中可以立馬做的事情!

創(chuàng)新互聯(lián)建站致力于互聯(lián)網(wǎng)網(wǎng)站建設(shè)與網(wǎng)站營銷,提供網(wǎng)站設(shè)計、成都網(wǎng)站制作、網(wǎng)站開發(fā)、seo優(yōu)化、網(wǎng)站排名、互聯(lián)網(wǎng)營銷、小程序開發(fā)、公眾號商城、等建站開發(fā),創(chuàng)新互聯(lián)建站網(wǎng)站建設(shè)策劃專家,為不同類型的客戶提供良好的互聯(lián)網(wǎng)應(yīng)用定制解決方案,幫助客戶在新的全球化互聯(lián)網(wǎng)環(huán)境中保持優(yōu)勢。
[[183082]]
我們一直在使用JavaScript的for循環(huán)。但現(xiàn)在,在最新的函數(shù)式編程技巧的支持下,過時的它應(yīng)該退休了。
幸運的是,你不必是一個函數(shù)式編程大師,也可以做出這個改變。更幸運的是,這就是你在眼前項目中可以立馬做的事情!
那到底JavaScript的for循環(huán)有什么問題?
for循環(huán)設(shè)計本身鼓勵改變狀態(tài)以及產(chǎn)生副作用,這兩者都是導(dǎo)致錯誤和不可預(yù)知代碼的隱患。
我們都知道全局狀態(tài)是糟糕的,應(yīng)該避免??墒?,局部狀態(tài)和全局狀態(tài)一樣糟糕,只是因為局部狀態(tài)處于一個較小的尺度中,沒有引起注意。因此,我們從來沒有真正解決問題,而是盡量把問題最小化。
對于可變的狀態(tài),在一些未知的時間點,變量會因為某些未知的原因而改變。這時,你要花上數(shù)小時進行調(diào)試,尋找這個值改變的原因。光為這,我都不知道自己掉了多少把頭發(fā)了。
下面,我想簡單談?wù)劯弊饔?。這個詞聽起來就煩人,副作用……媽蛋!難道你會希望自己的程序有什么副作用?當(dāng)然不!
但什么是副作用?
當(dāng)一個函數(shù)修改了其作用域以外的某些東西時,它就被視為有副作用??梢允歉淖円粋€變量的值、讀取鍵盤輸入、調(diào)用某個API、寫入磁盤數(shù)據(jù)、打印日志,等等。
副作用很強大,但同時也被承擔(dān)著重大的責(zé)任。
副作用應(yīng)該盡可能被消除,或者封裝在內(nèi)部,或可控。有副作用的函數(shù)難以測試,也難以推斷,所以要盡你所能甩掉它。幸好這里可以不用擔(dān)心副作用。
好了,閑話少說,上代碼。我們看一下這段或許你已經(jīng)看過上千次典型的for循環(huán):
- const cats = [
- { name: 'Mojo', months: 84 },
- { name: 'Mao-Mao', months: 34 },
- { name: 'Waffles', months: 4 },
- { name: 'Pickles', months: 6 }
- ]
- var kittens = []
- // 典型的拙劣寫法:for循環(huán)
- for (var i = 0; i < cats.length; i++) {
- if (cats[i].months < 7) {
- kittens.push(cats[i].name)
- }
- }
- console.log(kittens)
我計劃將這些代碼一步一步重構(gòu),讓你清楚地看到將這些代碼轉(zhuǎn)換成更漂亮的寫法是多么容易。
第一個改變就是把if里的聲明抽象為一個函數(shù):
- const isKitten = cat => cat.months < 7
- var kittens = []
- for (var i = 0; i < cats.length; i++) {
- if (isKitten(cats[i])) {
- kittens.push(cats[i].name)
- }
- }
通常,抽出if語句是個不錯的做法。過濾的著眼點從“小于7個月”轉(zhuǎn)變?yōu)椤笆且恢恍∝垺狈浅7浅V匾,F(xiàn)在,當(dāng)你再看這段代碼,意圖就變得清晰了。為什么要取得小于7個月的貓?一點都不明確。我們的意圖是找到小貓,所以讓代碼表示出來!
另一個好處是iskitten現(xiàn)在可復(fù)用了,而且我們都明白:
讓代碼可復(fù)用應(yīng)該始終是我們的目標(biāo)之一。
下一個改變就是提取出從對象貓到貓名字的轉(zhuǎn)換(或者映射)。這個變化對以后更有意義,現(xiàn)在只要相信我就好了:
- const isKitten = cat => cat.months < 7
- const getName = cat => cat.name
- var kittens = []
- for (var i = 0; i < cats.length; i++) {
- if (isKitten(cats[i])) {
- kittens.push(getName(cats[i]))
- }
- }
我本打算先介紹一下filter和map的,但轉(zhuǎn)念一想,還是直接展示引入它們之后的代碼多好理解,更能讓你體會到代碼可讀性的巨大變化:
- const isKitten = cat => cat.months < 7
- const getName = cat => cat.name
- const kittens =
- cats.filter(isKitten)
- .map(getName)
還要注意,我們已經(jīng)消除了 kittens.push(...)。不再有可變的狀態(tài),也不再有var!
使用const的代碼有如魔鬼般性感(超過了var和let)。
這里說明下,我們自始至終都可以使用const,因為const并不會使對象本身不可變(這個咱們下次再說)。別急,這里只是在講一個范例,所以先放我一馬!
重構(gòu)的最后一步就是把過濾和映射方法也提取到一個函數(shù)里(為了復(fù)用嘛,你懂的):
整合一起就是這樣:
- const isKitten = cat => cat.months < 7
- const getName = cat => cat.name
- const getKittenNames = cats =>
- cats.filter(isKitten)
- .map(getName)
- const cats = [
- { name: 'Mojo', months: 84 },
- { name: 'Mao-Mao', months: 34 },
- { name: 'Waffles', months: 4 },
- { name: 'Pickles', months: 6 }
- ]
- const kittens = getKittenNames(cats)
- console.log(kittens)
你會如何進一步分解這些函數(shù)?仔細想想“小于”或者name屬性、map或filter,說不定能有額外的收獲。你還可以研究下函數(shù)的復(fù)合,收益更大。
原 文:Rethinking JavaScript: Death of the For Loop
譯 文:眾成翻譯
作 者:camiler
分享名稱:反思JavaScript:論for循環(huán)的死亡
URL鏈接:http://www.5511xx.com/article/dhiidgs.html


咨詢
建站咨詢
