【譯】高階函數(shù):利用Filter幔摸、Map和Reduce來(lái)編寫(xiě)更易維護(hù)的代碼

原文:Higher Order Functions: Using Filter, Map and Reduce for More Maintainable Code
作者:Guido Schmitz
譯者:JeLewine

高階函數(shù)可以幫助你增強(qiáng)你的JavaScript流纹,讓你的代碼更具有聲明性堆缘。簡(jiǎn)單來(lái)說(shuō)掏颊,就是簡(jiǎn)單趣效,簡(jiǎn)練瘦癌,可讀。

知道什么時(shí)候和怎樣使用高階函數(shù)是至關(guān)重要的跷敬。它們可以讓你的代碼更容易理解和具有更好的可維護(hù)性讯私。它們也可以讓你很輕松的進(jìn)行函數(shù)間的組合。我們叫它復(fù)合函數(shù)干花,不過(guò)我不會(huì)在這里進(jìn)行詳細(xì)的介紹妄帘。在本文中,我將介紹JavaScript中三個(gè)最常用的高階函數(shù):.filter()池凄,.map()抡驼,.reduce

Filter

想象一下你正在編寫(xiě)一段代碼:有一個(gè)寫(xiě)滿不同人信息的列表肿仑,不過(guò)你想要過(guò)濾出一個(gè)大于等于18歲人的列表致盟。

我們的列表看起來(lái)就像下面這樣:

const people = [
 { name: ‘John Doe’, age: 16 },
 { name: ‘Thomas Calls’, age: 19 },
 { name: ‘Liam Smith’, age: 20 },
 { name: ‘Jessy Pinkman’, age: 18 },
];

我們先來(lái)看看第一個(gè)高階函數(shù)是如何篩選出大于等于18歲人的栗子。為了簡(jiǎn)潔尤慰,我將使用ES6標(biāo)準(zhǔn)中的箭頭函數(shù)馏锡。這是一種非常簡(jiǎn)潔的定義函數(shù)的方式,可以讓我們不必再寫(xiě)functionreturn伟端,以及一些括號(hào)杯道、大括號(hào)和分號(hào)。

const peopleAbove18 = (collection) => {
  const results = [];
 
  for (let i = 0; i < collection.length; i++) {
    const person = collection[i];
 
    if (person.age >= 18) {
      results.push(person);
    }
  }
  return results;
};

那現(xiàn)在如果我們想要篩選出18~20歲之間的人呢责蝠?

const peopleBetween18And20 = (collection) => {
  const results = [];
 
  for (let i = 0; i < collection.length; i++) {
    const person = collection[i];
 
    if (person.age >= 18 && person.age <= 20) {
      results.push(person);
    }
  }
  return results;
};

你可能已經(jīng)意識(shí)到了這里有許多重復(fù)的代碼党巾。我們可以抽象出一個(gè)通用的解決方案。這兩個(gè)函數(shù)有一些共同點(diǎn)霜医。它們都在一個(gè)列表中進(jìn)行迭代齿拂,并且在給定的條件下進(jìn)行過(guò)濾。

"高階函數(shù)是一個(gè)將一個(gè)或多個(gè)函數(shù)作為參數(shù)的函數(shù)"——ClojureBridge

我們可以通過(guò)使用更具聲明性的.filter()方法來(lái)改進(jìn)我們之前的函數(shù)肴敛。

const peopleAbove18 = (collection) => {
  return collection
    .filter((person) => person.age >= 18);
}

太棒了!我們通過(guò)使用高階函數(shù)減少了許多額外的代碼署海。同時(shí)也讓我們的代碼更具可讀性吗购。我們不在乎如何過(guò)濾東西,我們只是希望它被過(guò)濾砸狞。這篇文章稍后會(huì)介紹組合函數(shù)捻勉。

Map

讓我們拿著剛剛的人員名單和一個(gè)其中喜歡喝咖啡的人員名單。

const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’];

用命令式的實(shí)現(xiàn)方式就像下面這樣:

const addCoffeeLoverValue = (collection) => {
  const results = [];
 
  for (let i = 0; i < collection.length; i++) {
    const person = collection[i];
    if (coffeeLovers.includes(person.name)) {
      person.coffeeLover = true;
    } else {
      person.coffeeLover = false;
    }
 
    results.push(person);
  }
 
  return results;
};

我們可以利用.map()來(lái)讓代碼更具有聲明性:

const incrementAge = (collection) => {
  return collection.map((person) => {
    person.coffeeLover = coffeeLovers.includes(person.name);
 
    return person;
  });
};

再說(shuō)一遍刀森,.map()是一個(gè)高階函數(shù)贯底。它允許我們將一個(gè)函數(shù)作為參數(shù)傳遞。

Reduce

我敢打賭撒强,當(dāng)你知道什么時(shí)候和怎樣使用它的時(shí)候,你會(huì)喜歡上這個(gè)函數(shù)笙什。.reduce()很酷飘哨,上面提到的的大部分函數(shù)都可以通過(guò)它來(lái)實(shí)現(xiàn)。

讓我們先舉一個(gè)簡(jiǎn)單的栗子琐凭。我們想計(jì)算所有人年齡的和芽隆。當(dāng)然了,我們還是會(huì)首先看看如何用命令式的方式實(shí)現(xiàn)统屈。它基本上就是通過(guò)循環(huán)來(lái)增加總年齡變量胚吁。

const sumAge = (collection) => {
  let num = 0;
 
  collection.forEach((person) => {
    num += person.age;
  });
 
  return num;
}

接下來(lái)是使用.reduce()的聲明式方法:

const sumAge = (collection) => collection.reduce((sum, person) => {
 return sum + person.age;
}, 0);

我們甚至可以使用.reduce()來(lái)創(chuàng)建我們自己的.map().filter()

const map = (collection, fn) => {
  return collection.reduce((acc, item) => {
    return acc.concat(fn(item));
  }, []);
}
const filter = (collection, fn) => {
  return collection.reduce((acc, item) => {
    if (fn(item)) {
      return acc.concat(item);
    }
 
    return acc;
  }, []);
}

一開(kāi)始這一塊兒可能比較難理解愁憔。不過(guò)腕扶,.reduce()做的基本上就是以一個(gè)集合和一個(gè)定義了初始值的變量開(kāi)始。然后吨掌,遍歷該集合并將值添加到變量中去半抱。

組合map,filter和reduce

太好了膜宋,這些函數(shù)我們都有了窿侈。而且很重要的一點(diǎn)是,他們都存在于JavaScript的數(shù)組原型上秋茫。這意味著我們可以同時(shí)使用它們史简。這可以讓我們輕松創(chuàng)建各種可復(fù)用的函數(shù),減少編寫(xiě)某些功能所需要的代碼量肛著。

我們已經(jīng)討論過(guò)了如何利用.filter()來(lái)過(guò)濾出大于等于18歲的人圆兵;利用.map()來(lái)添加coffeeLover屬性;通過(guò).reduce()來(lái)計(jì)算所有人年齡的和〔咂現(xiàn)在衙傀,我們寫(xiě)一點(diǎn)代碼將這三個(gè)步驟合并起來(lái)。

const people = [
 { name: ‘John Doe’, age: 16 },
 { name: ‘Thomas Calls’, age: 19 },
 { name: ‘Liam Smith’, age: 20 },
 { name: ‘Jessy Pinkman’, age: 18 },
];
const coffeeLovers = [‘John Doe’, ‘Liam Smith’, ‘Jessy Pinkman’];
const ageAbove18 = (person) => person.age >= 18;
const addCoffeeLoverProperty = (person) => {
 person.coffeeLover = coffeeLovers.includes(person.name);
 
 return person;
}
const ageReducer = (sum, person) => {
 return sum + person.age;
}, 0);
const coffeeLoversAbove18 = people
 .filter(ageAbove18)
 .map(addCoffeeLoverProperty);
const totalAgeOfCoffeeLoversAbove18 = coffeeLoversAbove18
 .reduce(ageReducer);
const totalAge = people
 .reduce(ageReducer);

如果你用命令式方法的話萨咕,你最后會(huì)寫(xiě)一堆重復(fù)代碼统抬。

通過(guò).map().reduce().filter()來(lái)創(chuàng)建函數(shù)的思維將會(huì)極大的提高你的代碼質(zhì)量。而且可以增加可讀性聪建。你根本不必在意函數(shù)內(nèi)到底發(fā)生了什么钙畔,它非常容易理解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末金麸,一起剝皮案震驚了整個(gè)濱河市擎析,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挥下,老刑警劉巖揍魂,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異棚瘟,居然都是意外死亡现斋,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)偎蘸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)庄蹋,“玉大人,你說(shuō)我怎么就攤上這事迷雪∠奘椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵章咧,是天一觀的道長(zhǎng)倦西。 經(jīng)常有香客問(wèn)我,道長(zhǎng)赁严,這世上最難降的妖魔是什么调限? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮误澳,結(jié)果婚禮上耻矮,老公的妹妹穿的比我還像新娘。我一直安慰自己忆谓,他們只是感情好裆装,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著倡缠,像睡著了一般哨免。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昙沦,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天琢唾,我揣著相機(jī)與錄音,去河邊找鬼盾饮。 笑死采桃,一個(gè)胖子當(dāng)著我的面吹牛懒熙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播普办,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼工扎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衔蹲?” 一聲冷哼從身側(cè)響起肢娘,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舆驶,沒(méi)想到半個(gè)月后橱健,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沙廉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年畴博,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蓝仲。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖官疲,靈堂內(nèi)的尸體忽然破棺而出袱结,到底是詐尸還是另有隱情,我是刑警寧澤途凫,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布垢夹,位于F島的核電站,受9級(jí)特大地震影響维费,放射性物質(zhì)發(fā)生泄漏果元。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一犀盟、第九天 我趴在偏房一處隱蔽的房頂上張望而晒。 院中可真熱鬧,春花似錦阅畴、人聲如沸倡怎。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)监署。三九已至,卻和暖如春纽哥,著一層夾襖步出監(jiān)牢的瞬間昆汹,已是汗流浹背控汉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓禽炬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子垦写,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容