在项目实践中用更优雅的方式处理数组问题

栏目: JavaScript · 发布时间: 5年前

内容简介:写于 2017.07.04在最近的项目中,遇到了比较多处理数组的场景,比如要对数组里面某个元素的某一个字段进行抽取归类,或者判断数组当中的某个元素是否符满足判断条件等。网上关于使用ES5新的的API来代替for循环的文章已经非常多,它们有的详细讨论了API的用法,有的详细分析各自的性能,还有的整理了使用中的注意事项。因此,本文不再对这些API的详细使用方式进行赘述,仅仅从个人角度出发,整理归纳一些在项目实践中遇到的能够更加优雅处理数组遍历的例子。

写于 2017.07.04

在项目实践中用更优雅的方式处理数组问题

在最近的项目中,遇到了比较多处理数组的场景,比如要对数组里面某个元素的某一个字段进行抽取归类,或者判断数组当中的某个元素是否符满足判断条件等。

网上关于使用ES5新的的API来代替for循环的文章已经非常多,它们有的详细讨论了API的用法,有的详细分析各自的性能,还有的整理了使用中的注意事项。因此,本文不再对这些API的详细使用方式进行赘述,仅仅从个人角度出发,整理归纳一些在项目实践中遇到的能够更加优雅处理数组遍历的例子。

1、使用 Set 处理数组去重和元素剔除问题

Set 是es6新增的一种 数据结构 ,它和数组非常相似,但是成员的值都是唯一的,没有重复的值。它提供了4个语义化的API:

add(value)
delete(value)
has(value)
clear()

参考自@阮一峰 老师的《ECMAScript 6 入门》

那么我们可以用 Set 来干嘛呢?

第一个用法,数组去重。对于一个一维数组,我们可以先把它转化成 Set ,再配合 ... 解构运算符重新转化为数组,达到去重的目的。请看例子:

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]
复制代码

2、 使用 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 ]
复制代码

3、使用 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 }
]
*/
复制代码

4、借助 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() ,是因为要对比两个“对象元素”是否相等,是无法直接以“对象”形式比较的(永远返回不相等)。

5、后记

本文篇幅较短,难度也相对简单,以上都是一些平时实践中发现的技巧,希望可以对读者们有所启发。如果你也有一些比较优雅好玩的技巧,不妨和我交流分享喔~


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Flexible Pattern Matching in Strings

Flexible Pattern Matching in Strings

Gonzalo Navarro、Mathieu Raffinot / Cambridge University Press / 2007-7-30 / USD 64.99

String matching problems range from the relatively simple task of searching a single text for a string of characters to searching a database for approximate occurrences of a complex pattern. Recent ye......一起来看看 《Flexible Pattern Matching in Strings》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具