在項目實踐中用更優雅的方式處理數組問題

圖片描述

在最近的項目中,遇到了比較多處理數組的場景,好比要對數組裏面某個元素的某一個字段進行抽取歸類,或者判斷數組當中的某個元素是否符知足判斷條件等。javascript

網上關於使用ES5新的的API來代替for循環的文章已經很是多,它們有的詳細討論了API的用法,有的詳細分析各自的性能,還有的整理了使用中的注意事項。所以,本文再也不對這些API的詳細使用方式進行贅述,僅僅從我的角度出發,整理概括一些在項目實踐中遇到的可以更加優雅處理數組遍歷的例子。java

一、使用Set處理數組去重和元素剔除問題

Set是es6新增的一種數據結構,它和數組很是類似,可是成員的值都是惟一的,沒有重複的值。它提供了4個語義化的API:es6

  1. add(value):添加某個值,返回Set結構自己。數組

  2. delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。數據結構

  3. has(value):返回一個布爾值,表示該值是否爲Set的成員。性能

  4. clear():清除全部成員,沒有返回值。spa

參考自@阮一峯 老師的《ECMAScript 6 入門》code

那麼咱們能夠用Set來幹嗎呢?對象

第一個用法,數組去重。對於一個一維數組,咱們能夠先把它轉化成Set,再配合...解構運算符從新轉化爲數組,達到去重的目的。請看例子:blog

const arr = [1, 1, 2, 2, 3, 4, 5, 5]

const newArr = [...new Set(arr)]

console.log(newArr)

// [1, 2, 3, 4, 5]

值得注意的是,這個方法不能對元素爲「對象」的數組奏效:

const arr = [{ name: 'Alice', age: 12 }, { name: 'Alice', age: 12 }, { name: 'Bob', age: 13 }]

const newArr = [...new Set(arr)]

console.log(newArr)

// [{ name: 'Alice', age: 12 }, { name: 'Alice', age: 12 }, { name: 'Bob', age: 13 }]

這是由於Set判斷元素是否重複的辦法相似於===運算符,兩個對象老是不相等的。

除了去重,Set提供的delete()方法也是很是實用。在以往的作法中,若是要刪除數組中指定的元素,咱們須要先獲取該元素所在下標,而後經過splice()方法去刪除對應下標的元素,在理解上容易引發混亂:

// 我想刪除數組當中值爲2的元素
const arr = [1, 2, 3]
const index = arr.indexOf(2)
if (index !== -1) {
    arr.splice(index, 1)
}

console.log(arr)

// [1, 3]

使用Set就清晰多了:

const arr = [1, 2, 3]
const set = new Set(arr)
set.delete(2)
arr = [...set]

console.log(arr)

// [1, 3]

二、 使用map()方法和對象解構語法提取字段

請求後臺接口返回的數據中,極可能會遇到下面這種數據格式:

studentInfo = [
  { name: 'Alice', age: 18, no: 2 },
  { name: 'Bob', age: 16, no: 5 },
  { name: 'Candy', age: 17, no: 3 },
  { name: 'Den', age: 18, no: 4 },
  { name: 'Eve', age: 16, no: 1 },
]

當咱們要獲取姓名列表、年齡列表和編號列表的時候,咱們能夠經過map()再配合對象的解構語法方便快捷地進行處理:

const nameList = studentInfo.map(({ name }) => name)
const ageList = studentInfo.map(({ age }) => age)
const noList = studentInfo.map(({ no }) => no)

// nameList: [ 'Alice', 'Bob', 'Candy', 'Den', 'Eve' ]
// ageList: [ 18, 16, 17, 18, 16 ]
// noList: [ 2, 5, 3, 4, 1 ]

三、使用filter()方法和對象解構語法過濾數組

接上上面的例子,若是我想獲取一個「年齡小於等於17歲」的新列表,應該怎麼作呢?相似map()方法,咱們能夠用filter()方法進行過濾:

const newStudentInfo = studentInfo.filter(({ age }) => {
  return age <= 17
})

/*
newStudentInfo: [
  { name: 'Bob', age: 16, no: 5 },
  { name: 'Candy', age: 17, no: 3 },
  { name: 'Eve', age: 16, no: 1 }
]
*/

四、藉助includes()方法求兩個數組的差集

假設咱們有如下兩個數組:

var a = [1, 2, {s:3}, {s:4}, {s:5}]
var b = [{s:2}, {s:3}, {s:4}, 'a']

咱們應該如何找到它們的差集呢?傳統的方法可能須要把它們以Object形式hash化,但其實咱們能夠經過.includes()方法更加優雅方便地找出差集,代碼以下:

var a = [1, 2, {s:3}, {s:4}, {s:5}].map(item => JSON.stringify(item))
var b = [{s:2}, {s:3}, {s:4}, 'a'].map(item => JSON.stringify(item))

var diff = a.concat(b)
            .filter(v => !a.includes(v) || !b.includes(v))
            .map(item => JSON.parse(item))
            
// diff: [1, 2, {s:5}, {s:2}, "a"]

至於爲何要JSON.stringify(),是由於要對比兩個「對象元素」是否相等,是沒法直接以「對象」形式比較的(永遠返回不相等)。

五、後記

本文篇幅較短,難度也相對簡單,以上都是一些平時實踐中發現的技巧,但願能夠對讀者們有所啓發。若是你也有一些比較優雅好玩的技巧,不妨和我交流分享喔~

相關文章
相關標籤/搜索