讲讲 ES6 的一些数组的新方法吧,之前面试有问到,自己用了一下还挺好用,先看看数组新方法的列表
- 扩展运算符
- Array.from()
- Array.of()
- copyWithin()
- find() findIndex()
- fill()
- entries() keys() values()
- includes()
- flat() flatMap()
扩展运算符
在 ES5 中我们要将两个打散数组合并会用到数组对象的 concat 方法
let arr = [1,2,3,4,5,6,7,8,9,0]
console.log(arr.concat([1],[1,2,3,4],'aaaa',['bbbb','dddd'])) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 1, 2, 3, 4, "aaaa", "bbbb", "dddd"]
concat 方法最终会返回一个拼接完的数组,也就是我们所需的结果
如果用扩展运算符又是如何操作呢?
let arr = [1,2,3,4,5,6,7,8,9,0]
console.log(...arr) //1 2 3 4 5 6 7 8 9 0
let arr2 = [...arr,...[1],...[1,2,3,4],'aaaa',...['bbbb','dddd']]
console.log(arr2) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 1, 2, 3, 4, "aaaa", "bbbb", "dddd"]
不仅可以打散数组,扩展运算符也可以打散字符串
console.log([...'hello world']) //['h','e','l','l','o','','w','o','r','l','d']
当然也能运用于数组的解构赋值
let [a,...b] = [1,2,3,4,5,6]
console.log(a)//1
console.log(b)//[2,3,4,5,6]
// 但是必须要知道的一点是在进行数组的解构赋值时只能作用于数组的最后一位,不然会报错!let[...c,d] = [22,33,44,55] //Uncaught SyntaxError: Rest element must be last element
当然也可以和 Aray.from()一样,将一个类数组转换成数组
let set = new Set([1,2,3,4,5,6,7,8])
console.log([...set]) //[1, 2, 3, 4, 5, 6, 7, 8]
运行后可知,… 可将 Array 对象打散,在数组中打散则会返回一个新的数组,对于使用长逻辑时,有时候 concat 可能会使代码看起来并不是很易懂,用这个会好很多。但是扩展运算符并不是主要用来打散重组数组的。把它用在方法传参中,会用起来很简洁灵活
let arr = [1,2,3,4,5,6,7,8,9,0]
function add(...arr){let aaa = arguments[0].reduce((i,j)=>{return i+j})
console.log(aaa)//45
}
add(arr)
当然也可以这样子做
function testFoo(a,b,c,d){return a+b+c+d}
let arr = [1,2,3,4]
testFoo(...arr)
Array.from()
将类数组对象和迭代器对象转换成数组最常用的应该就是数组去重操作了
let arr = [1,2,3,3,3,3,444,4,4,4,5,5,'a','a','b','f']
let set = new Set(arr) //set 数据类型中不会存在相同的元素,因此把数组转换成 set 会将数组中重复的部分去除
let newArr = Array.from(set) // 将 set 数据类型转换成数组
console.log(newArr) //[1, 2, 3, 444, 4, 5, "a", "b", "f"]
当然它也能像扩展运算符一样,将 String 字符串转换成数组
let str = 'hello world'
let arr = Array.from(str)
console.log(arr)//['h','e','l','l','o','','w','o','r','l','d']
这里要了解一个概念什么是类数组对象一般来说,类数组对象和数组没多大区别在操作上也是
let likeArr = {
'0':0,
'1':1,
'2':'aa',
'3':'bb',
'4':'cc',
'length':5
} // 是不是和你控制台打印出来的数组对象很像甚至可以这样子做
console.log(likeArr[4])//cc
// 我们可以用 Array.from()将其转换成真正的数组
let arr = Array.from(likeArr)
console.log(arr)//[0, 1, "aa", "bb", "cc"]
在刚刚操作过程中我第一次在创建类数组对象时忘记定义 length 属性了,于是控制台报错了,说白了类数组对象都有一个 length 属性,如果没有则和普通对象没多大区别当然 Array.from()也会控制台报错,当然扩展运算符是不能将类数组对象转换成数组的,但是 Array.from()可以,对此我们可以用代码进行验证
let likeArr = {length:3}
console.log(Array.from(likeArr))//[undefined,undefined,undefined]
console.log(...likeArr)//Uncaught TypeError: Found non-callable @@iterator
我特地试了一下 map 数据类型
let map = new Map()
map.set('0','a').set('1','b')
let arr = Array.from(map)
console.log(arr) //[["0","a"],["1","b"]]
发现 map 数据类型可以被 Array.from()转换但是转换成的是一个数组是一个 [[‘ 键 ’,’ 值 ’],[‘ 键 ’,’ 值 ’],[‘ 键 ’,’ 值 ’]] 数组,一般也不会这么用我私下再去研究
Array.of()
Array.of()的作用是将一组值转换成数组,是不是和 concat 方法有点像,但是 concat 方法是作用于数组对象的,而且,如果传入的参数中包含数组是会将数组打散转换成独立值,而 Array.of()不同,存入数组,转换成数组后该参数在返回值中还是数组在文档中阮一峰大神是这样子来说明的
这个方法的主要目的,是弥补数组构造函数 Array()的不足。因为参数个数的不同,会导致 Array()的行为有差异。
举个例子
Array.of(0,1,2,3,4)//[0,1,2,3,4]
Array.of(0)//[0]
// 如果我们用传统的生成数组方式会是怎么样?new Array() //[]
// 传入一个参数
new Array(3)// 生成一个长度为 3 的数组 [undefined,undefined,undefined]
// 传入多个参
new Array(1,2)//[1,2]
从打印结果可知 Array 构造方法传入参数数量不同,返回的结果并不统一,而 Array.of()却是出奇的统一,这弥补了 Array 构造方法的不足
在不传入参数时 Array.of()会返回一个空数组
Array.of()//[]
数组对象的 copyWithin()方法
引用文档中的介绍:数组实例的 copyWithin 方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
改方法可接收三个参数:
(使用的不多,继续抄文档)
- target(必需):从该位置开始替换数据。如果为负值,表示倒数。
- start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
- end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数
let arr = [1,2,3,4,5,6,7,8,9]
console.log(arr.copyWithin(0,3,8))//[4, 5, 6, 7, 8, 6, 7, 8, 9]
let arr1 = [1,2,3,4,5,6,7,8,9]
console.log(arr1.copyWithin(0,5))//[6, 7, 8, 9, 5, 6, 7, 8, 9]
文档中有更详细的例子以下抄文档
// 将 3 号位复制到 0 号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]
// - 2 相当于 3 号位,- 1 相当于 4 号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]
// 将 3 号位复制到 0 号位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}
// 将 2 号位到数组结束,复制到 0 号位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// 对于没有部署 TypedArray 的 copyWithin 方法的平台
// 需要采用下面的写法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
数组对象 find() findIndex()
find()用于找寻数组对象中第一个符合条件的值传入参数是一个回调函数由此可见是一个高阶函数,该方法类似数组对象的 every()方法 some()方法 filter()方法,用于鉴别数组中的值,回调方法传入参数也类似都是必传 value(值),可选 index(索引),与 arr(原数组)具体差别用实验来鉴别
let arr = [1,2,3,4,5,6,7,8,9]
//every()方法用于鉴别数组的所有元素是否符合要求并返回 boolean
arr.every((value,index,arr)=>{return value===7&&index===6})//false
//some()方法用于鉴别数组中是否有符合要求的值并返回 boolean
arr.some((value,index,arr)=>{return value===7&&index===6})//true
//filter()方法将数组中符合要求的值拼接成一个新数组并返回
arr.filter(value=>{return value>3})//[4, 5, 6, 7, 8, 9]
//find()方法返回数组中符合要求的第一个值
arr.find((value)=>{return value>3})//4
// 若没有符合要求的值则返回 undifined
arr.find((value)=>{return value>100})//undifined
findIndex 的用法和 find 一样,但是返回值不同,find 方法是返回符合条件的第一个值,若没有符合要求的值则返回 undifined。findIndex 则是返回符合条件的第一个值在数组中的位置,若没有符合要求的值则返回 -1
arr.findIndex(value=>{return value>3})//3
arr.findIndex(value=>{return value>100})//-1
数组对象的 fill()方法
用于填充数组对象并返回新数组,会改变原数组例子如下
let arr = Array(3)// 长度为 3 的数组 =>[undefined,undefined,undefined]
arr.fill(666) //[666,666,666]
console.log(arr) //[666,666,666]
let arr1 = [1,2,3,5,4]
arr1.fill(2333)//[2333, 2333, 2333, 2333, 2333]
迭代器遍历对象 entries() keys() values()
自己知道是怎么一回事但是不知道怎么解释,继续引用文档中的解释:ES6 提供三个新的方法——entries(),keys()和 values()——用于遍历数组。它们都返回一个遍历器对象,可以用 for…of 循环进行遍历,唯一的区别是 keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。
let arr = [1,2,3,4,5,6,7,8,9]
for (let index of arr.keys()) {
// 返回 key 值
console.log(index); //0 1 2 3 4 5 6 7 8
}
for (let index of arr.values()){
// 返回 value 值
console.log(index); //0 1 2 3 4 5 6 7 8
}
for (let index of arr.entries()){
// 返回键值对
console.log(index) //[0,1],[1,2],[2,3]........
}
也能配合数组对象的其他高阶函数使用,比如我要创建一个包含过去 7 天 Date 的数组
let dateArr = [...Array(7).keys()].map(d=>new Date(Date.now()-d*1000*24*60))
//[Tue May 28 2019 13:27:00 GMT+0800 (中国标准时间), Tue May 28 2019 13:03:00 GMT+0800 (中国标准时间), Tue May 28 2019 12:39:00 GMT+0800 (中国标准时间), Tue May 28 2019 12:15:00 GMT+0800 (中国标准时间), Tue May 28 2019 11:51:00 GMT+0800 (中国标准时间), Tue May 28 2019 11:27:00 GMT+0800 (中国标准时间), Tue May 28 2019 11:03:00 GMT+0800 (中国标准时间)]
// 或者说生成一个 0 到 9 的数组
let numArr = [...Array(10).keys()].map(n=>n)
//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
如果不适用 Array.from()或者扩展运算符与高阶函数配合或者不用 for of 循环进行配合则需要用到迭代器的 next()方法进行往下操作
let arr = ['a','b','c','d','e']
let keysData = arr.keys()
console.log(keysData.next().value)//0
console.log(keysData.next().value)//1
console.log(keysData.next().value)//2
let valuesData = arr.values()
console.log(valuesData.next().value)//a
console.log(valuesData.next().value)//b
console.log(valuesData.next().value)//c
let entriesData = arr.entries()
console.log(entriesData.next().value)//[0,'a']
console.log(entriesData.next().value)//[1,'b']
console.log(entriesData.next().value)//[2,'c']
关于 ES6 迭代器其他操作可自己去理解
数组对象的 includes()方法
非常好用的一个方法,用于判断数组中是否包含某个值若有则返回 true,没有则返回 false
let arr = [1,2,3,4,5]
arr.includes(2)//true
arr.includes(6)//false
改方法可以传入两个参数,第一个是用于判断是否存在的值,第二个是判断开始位置
let arr = [1,2,3,4,5]
arr.includes(2,3) //false
arr.includes(4,3) //true
数组对象的 flat() flatMap()方法
flat()方法将数组中的数组打散生成一个新的数组,不改变原数组,不好理解是不是?!那还是看例子吧
let arr = [1,2,3,[4,5,6],7,[8,9]]
let newArr = arr.flat() //[1, 2, 3, 4, 5, 6, 7, 8, 9]
但是 flat()方法只能打散一层数组,如果数组中嵌套的数组是多维数组则需要传入参数(Number 类型),要打散几维数组则传几默认是 1
let arr = [1,[2,[3,4,[5,6]]],7]
arr.flat(2) //[1,2,3,4,[5,6],7]
arr.flat(3) //[1,2,3,4,5,6,7]
如果不管数组中有几维数组都要将数组打散成一维数组的话可以传入关键字 Infinity
let arr = [1,[2,[3,[4,[5,[6,[7,[8]]]]]]],9]
arr.flat(Infinity)//[1,2,3,4,5,6,7,8,9]
flatMap()方法与 flat()类似,都能打散数组,但是 flatMap()只能打散一层并且 flatMap()与 map 类似可以传入一个回调函数作为参数,并且返回一个新数组
let arr = [1,[2,[3,[4,[5,[6,[7,[8]]]]]]],9]
let mapArr = arr.flatMap(i=>{return typeof(i)
})//["number", "object", "number"]
flatMap()方法回调函数参数也与 map()方法回调函数参数相同都可以传入 value(值,必填),key(索引,选填),arr(原数组,选填)
差不多就这点,主要是我写累了就不写了吧