自從學會了 Array.reduce() ,再也離不開它

(轉載)原文連接:http://www.javashuo.com/article/p-gbinpznj-z.html
自從學會了 Array.reduce() ,再也離不開它html

在全部後 ES6 時代的數組方法中,我以爲最難理解的就是Array.reduce()面試

從表面上看,它彷佛是一個簡單無趣的方法,並無太大做用。 可是在不起眼的外表之下,Array.reduce()其實是對開發人員工具包的強大而靈活的補充。數組

今天,咱們就來研究一下經過Array.reduce()能夠完成的一些有意思的事情。瀏覽器

原理

大部分現代的數組方法都返回一個新的數組,而 Array.reduce() 更加靈活。它能夠返回任意值,它的功能就是將一個數組的內容聚合成單個值。服務器

這個值能夠是數字、字符串,甚至能夠是對象或新數組。這就是一直難住個人部分,我沒想到它這麼靈活!ide

用法

Array.reduce()接受兩個參數:一個是對數組每一個元素執行的回調方法,一個是初始值。函數

這個回調也接受兩個參數:accumulator是當前聚合值,current是數組循環時的當前元素。不管你返回什麼值,都將做爲累加器提供給循環中的下一個元素。初始值將做爲第一次循環的累加器。工具

var myNewArray = [].reduce(function (accumulator, current) {
  return accumulator;
}, starting);

讓咱們來看幾個實際例子。post

1. 數組求和

假設你想把一組數字加在一塊兒。使用Array.forEach()大概能夠這麼作:性能

var total = 0;

[1, 2, 3].forEach(function (num) {
  total += num;
});

這是Array.reduce()用得最多的例子了。我發現 accumulator 這個單詞讓人困惑,因此在示例中我改成sum,由於這裏就是求和的意思。

var total = [1, 2, 3].reduce(function (sum, current) {
  return sum + current;
}, 0);

這裏傳入0做爲初始值。

在回調裏,將當前值加入到 sum,第一輪循環時它的值是初始值0,而後變成1(初始值0加上當前元素值1),而後變成3(累加值 1加上當前元素值 2 ),以此類推

2. 組合多個數組方法

假設有一個wizards 數組:

var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'
  }
];

你想建立一個僅包含住在 Hufflepuff 的巫師名字的新數組。一個可行的方法是使用Array.filter() 方法獲取 house 屬性爲Hufflepuff的 wizards 。而後用Array.map() 方法建立一個只包含過濾後對象的name 屬性的新數組。

var hufflepuff = wizards.filter(function (wizard) {
  return wizard.house === 'Hufflepuff';
}).map(function (wizard) {
  return wizard.name;
});

使用Array.reduce() 方法,咱們能夠用一步獲得一樣的結果,提升了性能。傳遞一個空數組[]做爲初始值。每次循環時判斷wizard.house 是否爲Hufflepuff。若是是,就加入到newArr 中(即accumulator),不然啥也不作。

不管判斷條件是否成立,最後都返回 newArr 做爲下一次循環的accumulator 。

var hufflepuff = wizards.reduce(function (newArr, wizard) {
  if (wizard.house === 'Hufflepuff') {
    newArr.push(wizard.name);
  }
  return newArr;
}, []);

3. 從數組生成 HTML 標籤

那麼,若是想建立一個由住在 Hufflepuff 的巫師組成的無序列表要怎麼作呢?此次不是給Array.reduce()傳一個空數組做爲初始值了,而是一個名爲 html的空字符串''

若是wizard.house 等於 Hufflepuff,咱們就將wizard.name 用列表項li包裹起來,再拼接到html 字符串裏。而後返回html 做爲下一次循環的accumulator 。

var hufflepuffList = wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, '');

Array.reduce()先後添加無序列表的開始和結束標記,就能夠把它插入到 DOM 中了。

var hufflepuffList = '<ul>' + wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, '') + '</ul>';

4. 數組元素分組

lodash 有個 groupBy()方法,能夠將數組元素按照某個標準分組。

假設你有一個數字數組。

若是你想把numbers 數組中的元素按照整數部分的值分組,用 lodash 能夠這樣作:

var numbers = [6.1, 4.2, 6.3];

// 返回 {'4': [4.2], '6': [6.1, 6.3]}
_.groupBy(numbers, Math.floor);

若是你有一個單詞數組,你想根據 words 中的單詞長度分組,你能夠這樣作:

var words = ['one', 'two', 'three'];

// 返回 {'3': ['one', 'two'], '5': ['three']}
_.groupBy(words, 'length');

用 Array.reduce() 實現 groupBy()函數

你能夠用Array.reduce() 方法實現一樣的功能。

咱們來建立一個工具函數groupBy(),接受數組和分組條件做爲參數。在groupBy()內部,在數組上執行Array.reduce() ,傳一個空對象{}做爲初始值,而後返回結果。

var groupBy = function (arr, criteria) {
  return arr.reduce(function (obj, item) {
    // 省略代碼
  }, {});
};

在 Array.reduce() 回調函數內部,咱們會判斷criteria是函數仍是 item的屬性。而後獲取當前item的值。

若是obj 中還不存在這個屬性,則建立它,並將一個空數組賦值給它。最後,將item 添加到 key的數組中,再返回該對象做爲下一次循環的accumulator 。

var groupBy = function (arr, criteria) {
  return arr.reduce(function (obj, item) {

    // 判斷criteria是函數仍是屬性名
    var key = typeof criteria === 'function' ? criteria(item) : item[criteria];

    // 若是屬性不存在,則建立一個
    if (!obj.hasOwnProperty(key)) {
      obj[key] = [];
    }

    // 將元素加入數組
    obj[key].push(item);

    // 返回這個對象
    return obj;

  }, {});
};

5. 合併數據到單個數組

還記得前面的wizards數組嗎?

var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'
  }
];

若是還有另外一份數據,每一個巫師得到的的積分對象:

var points = {
  HarryPotter: 500,
  CedricDiggory: 750,
  RonaldWeasley: 100,
  HermioneGranger: 1270
};

假設你想把兩份數據合併到一個數組,也就是把 points 數值添加到每一個巫師對象上。你會怎麼作?

Array.reduce() 方法特別適合!

var wizardsWithPoints = wizards.reduce(function (arr, wizard) {

  // 移除巫師名字中的空格,用來獲取對應的 points
  var key = wizard.name.replace(' ', '');

  // 若是wizard有points,則加上它,不然設置爲0
  if (points[key]) {
    wizard.points = points[key];
  } else {
    wizard.points = 0;
  }

  // 把wizard對象加入到新數組裏
  arr.push(wizard);

  // 返回這個數組
  return arr;

}, []);

其實這裏用Array.map也很方便實現。

6. 合併數據到單個對象

若是你想合併兩個來源的數據到一個對象中,也就是巫師的名字做爲屬性名,house 和 points 做爲屬性值,要怎麼作呢?一樣, Array.reduce() 很合適。

var wizardsAsAnObject = wizards.reduce(function (obj, wizard) {

  // 移除巫師名字中的空格,用來獲取對應的 points
  var key = wizard.name.replace(' ', '');

  // 若是wizard有points,則加上它,不然設置爲0
  if (points[key]) {
    wizard.points = points[key];
  } else {
    wizard.points = 0;
  }

  // 刪除 name 屬性
  delete wizard.name;

  // 把 wizard 數據添加到新對象中
  obj[key] = wizard;

  // 返回該對象
  return obj;

}, {});

總結: Array.reduce() 真香

Array.reduce() 方法從我曾經認爲不堪大用的東西,變成我最喜歡的 JavaScript 方法。那麼,你應該使用它嗎?何時能夠用?

Array.reduce() 方法有着良好的瀏覽器支持。全部的現代瀏覽器都支持,包括 IE9 及以上。移動端瀏覽器也在很早以前就支持了。若是你還須要支持更老的瀏覽器,你能夠添加一個 polyfill 來支持到 IE6

Array.reduce()最大的槽點可能就是對於歷來沒接觸過的人來講有點費解。組合使用Array.filter() 和Array.map()執行起來更慢,而且包含多餘的步驟,可是更容易閱讀,從方法名能夠明顯看出它要作的事情。

儘管如此,有時候Array.reduce() 也可讓複雜的事情看起來更簡單。 groupBy() 工具函數就是個很好的例子。

最後,它應該成爲你的工具箱裏的另外一個工具,一個使用得當就威力無窮的工具。

(轉載)原文連接:http://www.javashuo.com/article/p-gbinpznj-z.html

學習地址

超值推薦:

阿里雲雙12已開啓,雲產品冰點價,新用戶專享1折起,1核2G雲服務器僅需89元/年229元/3年。買了對於提高技術或者在服務器上搭建自由站點,都是很不錯的,若是本身有實際操做,面試+工做中確定是加分項。(老用戶能夠用家人或朋友的帳號購買,真心便宜&划算)

可「掃碼」或者「點擊購買 "

自從學會了 Array.reduce() ,再也離不開它

END

自從學會了 Array.reduce() ,再也離不開它

相關文章
相關標籤/搜索