前言
JavaScript 数组的真实力量隐藏在数组的属性和方法中,下面我们来重点介绍下数组的方法。
包括ES6新增的一些方法,但这些方法目前不是所有浏览器都支持,使用前请查阅官方文档的浏览器支持情况。
大纲
目前所有数组方法思维导图整理如下:
示例解析
检测数组
1、isArray()
该方法的目的就是确定一个值是否为数组, 而不用考虑在哪个全局执行上下文中创建的:
1 2 3
| if(Array.isArray(value)) { }
|
在只有一个全局作用域的情况下,使用instanceof
也可以:
1 2 3
| if(value instanceof Array) { }
|
迭代器方法
1、keys()、values()、entries()
在ES6中,Array原型上暴露了3个用于检索数组内容的方法
keys()
返回数组索引的迭代器
values()
返回数组元素的迭代器
entries()
返回索引/值对的迭代器
1 2 3 4 5 6 7 8 9 10
| const arr = ["foo", "bar"]
const aKeys = Array.from(arr.keys()) const aValues = Array.from(arr.values()) const aEntries = Array.from(arr.entries())
console.log(aKeys) console.log(aValues) console.log(aEntries)
|
使用ES6的解构,可以很快的在循环中拆分键值对:
1 2 3 4 5 6 7 8 9 10 11 12
| const arr = ["foo", "bar"]
for(const [idx, element] of arr.entries()) { console.log(idx) console.log(element) }
输出: 0 foo 1 bar
|
复制和填充方法
ES6新增的两个方法,使用这两个方法不会改变数组的大小
1、fill()
可以向一个已有的数组中插入全部或者部分相同的值
1 2 3 4 5 6 7 8 9 10 11 12 13
| const zeroes = [0,0,0,0,0]
zeroes.fill(5); console.log(zeroes)
zeroes.fill(6, 3) console.log(zeroes)
zeroes.fill(7, 1, 3) console.log(zeroes)
|
2、copyWithin()
会按照指定范围浅复制数组中的部分内容,然后将他们插入到指定索引开始的位置
1 2 3 4 5 6 7 8 9 10 11 12 13
| const ints = [1,2,3,4,5,6,7,8]
ints.copyWithin(5); console.log(ints)
ints.copyWithin(0, 5); console.log(ints)
ints.copyWithin(4, 0, 3); console.log(ints)
|
小结
fill()
与copyWithin()
相同点:
- 静默忽略超出数组边界、零长度及方向相反的索引范围
- 会改变原始数组元素,不改变数组长度
转换方法
1、toString
与toLocaleString()
1 2 3 4 5 6 7
| const arr = ['小罗', '小蔡']
const a1 = arr.toString() const a2 = arr.toLocaleString()
console.log(a1) console.log(a2)
|
2、join
1 2 3 4 5 6 7
| const arr = ['小罗', '❤️', '小蔡']
const a1 = arr.join('') const a2 = arr.join('#')
console.log(a1) console.log(a2)
|
3、valueOf()
返回数组本身
1 2 3 4 5
| const arr = ['小罗', '❤️', '小蔡']
const a1 = arr.valueOf()
console.log(a1)
|
栈方法
数组对象可以像栈一样,就是一种限制插入和删除项的数据结构。
栈是一种后进先出(LIFO
)的结构,也就是先添加的项先被删除。
数据项的插入(推入,push
)和删除(弹出,pop
)只在栈的一个地方发生,即栈顶。
1、push()
与pop()
1 2 3 4 5 6 7 8
| const arr = []; arr.push("red", "green") arr.push("black")
let item = arr.pop() console.log(item) console.log(arr.length)
|
栈方法可以与其他方法一起使用
1 2 3 4 5 6 7 8 9
| const arr = ["red", "green"]; arr.push("brown"); arr[3] = "black";
console.log(arr.length)
let item = arr.pop() console.log(item)
|
队列方法
队列以先进后出(FIFO
)形式限制访问。
1、shift()
与unshift()
使用shift()
和push()
,可以把数组当成队列使用。
1 2 3 4 5 6 7 8
| let arr = [] arr.push(1,2) arr.push(3)
let item = arr.shift() console.log(arr) console.log(item)
|
使用unshift()
和pop()
,可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据。
1 2 3 4 5 6 7
| let arr = [] arr.unshift(1,2) arr.unshift(3) console.log(arr)
let item = arr.pop() console.log(item)
|
排序方法
1、reverse()
将数组元素反向排序
1 2 3 4 5
| const arr = [1,2,3,4]
arr.reverse()
console.log(arr)
|
这个方法很直观, 但不够灵活, 故有了sort()
方法
2、sort()
会按照升序重新排列数组元素,即最小的值在前面,最大的值在后面。
为此,sort()
会在每一项上调用String()
转型函数,然后比较字符串来决定顺序。
即使数组元素都是数字,也会先把数组转换为字符串再比较、排序。 比如:
1 2 3 4 5
| const arr = [0,1,5,10,15]
arr.sort()
console.log(arr)
|
很明显,上述结果不是我们想要的,为此,sort()
方法可以接收一个比较函数, 该函数应返回负值、零值或正值,根据返回的(负、零、正)值对值进行排序(升序排列)。
比较函数接收两个参数a,b; a排在b前面,返回负值;a排在b后面,返回正值;a等于b,返回0。
升序排列
1 2 3 4 5
| const arr = [0,1,5,10,15]
arr.sort((a,b) => a < b ? -1 : a > b ? 1 : 0)
console.log(arr)
|
这样排序结果就正常了
降序排列
1 2 3 4 5
| const arr = [0,1,5,10,15]
arr.sort((a,b) => a < b ? 1 : a > b ? -1 : 0)
console.log(arr)
|
若数组元素是树值,或是其valueOf()
方法返回数值的对象(如Date
对象),比较函数可以写的更简单,如下:
1 2 3 4 5 6 7 8 9
| function compare(a,b) { return b - a }
function compare(a,b) { return a - b }
|
操作方法
1、concat()
通过合并(连接)现有数组来创建一个新数组
1 2 3 4 5 6
| let arr = [1,2,3,4]
let arr1 = arr.concat(5, [6,7])
console.log(arr) console.log(arr1)
|
打平数组参数的行为可以重写,方法是在参数数组上指定宇哥特殊的符号: Symbol.isConcatSpreadable
。 这个符号可以阻止concat()
打平参数数组,设置true
可以强制打平类数组对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| let arr = [1,2,3,4]
let newArr = [5,6] let moreNewArr = { [Symbol.isConcatSpreadable]: true, length: 2, 0: "pink", 1: "red" }
newArr[Symbol.isConcatSpreadable] = false
let arr2 = arr.concat("red", newArr)
let arr3 = arr.concat(moreNewArr)
console.log(arr2) console.log(arr3)
|
2、slice()
用于创建一个包含原有数组中一个或多个元素的新数组。
可接收一个或两个参数,若只有一个参数,则返回该索引到数组末尾的所有元素; 若有两个参数,返回从开始索引到结束索引对应的所有元素(其中不包括结束索引对应的元素)
1 2 3 4 5 6 7 8 9 10 11
| let arr = [1,2,3,4]
let arr1 = arr.slice(1) let arr2 = arr.slice(1,3)
let arr3 = arr.slice(-2,-1)
console.log(arr1) console.log(arr2) console.log(arr3)
|
3、splice()
或许最强大的数组方法就是splice()
, 使用它的方式有很多种。 它的主要目的是在数组中间插入元素,但有3中不同的方式使用了这个方法:
3.1、删除
需要给splice()
传递2个参数: 要删除的第一个元素的位置和要删除的元素数量。
1 2 3 4 5
| let arr = [1,2,3,4] let removed = arr.splice(0,2)
console.log(arr) console.log(removed)
|
3.2、插入
需要给splice()
传递3个参数: 开始位置(该位置元素在插入后被挤到后面)、 0(要删除的元素数量)、要插入的元素。
1 2 3 4 5
| let arr = [1,2,3,4] let removed = arr.splice(1,0,"red","blue")
console.log(arr) console.log(removed)
|
3.3、替换
需要给splice()
传递3个参数: 开始位置、要删除的元素数量、要插入的任意多个元素。
要删除的元素数量不一定和要插入的元素数量一致。
1 2 3 4 5
| let arr = [1,2,3,4] let removed = arr.splice(1,1,"red","blue")
console.log(arr) console.log(removed)
|
搜索和位置方法
严格相等的搜索方法
1、indexOf()
与lastIndexOf()
这两个方法都返回要查找的元素在数组中的位置,若没找到返回-1
2、includes()
该方法返回布尔值,表示是否至少找到一个与指定元素匹配的项。 若找到返回true
,未找到返回false
1 2 3 4 5 6 7 8 9 10 11 12 13
| const mudanPerson = ['毛毛', '乐乐', '蔡蔡', 'jeff', '小罗', '蔡蔡']
const firstIndex = mudanPerson.indexOf('蔡蔡') const lastIndex = mudanPerson.lastIndexOf('蔡蔡')
const isInclude = mudanPerson.includes('蔡蔡')
output: firstIndex ---> 2 lastIndex ---> 5 isInclude ---> true
|
断言函数搜索数组
1、find()
与 findIndex()
这两个方法都是从最小索引开始匹配,每个索引都会调用这个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const mudanPerson = [ {name: '小罗', age: 24, birthday: 1998, feature: '母单', isPretty: '是'}, {name: '毛毛', age: 22, birthday: 2000, feature: '母单', isPretty: '是'}, {name: 'Jeff', age: 25, birthday: 1997, feature: '母单', isPretty: '是'}, {name: '乐乐', age: 26, birthday: 1996, feature: '非母单',isPretty: '是'}, {name: '蔡蔡', age: 27, birthday: 1995, feature: '母单', isPretty: '是'},{name: '文婷', age: 24, birthday: 1998, feature: '母单', isPretty: '是'},{name: '烨子', age: 24, birthday: 1998, feature: '母单', isPretty: '是'},{name: '奇奇', age: 27, birthday: 1995, feature: '非母单',isPretty: '是'}, {name: '团团', age: 22, birthday: 2000, feature: '母单', isPretty: '是'}]
const result = mudanPerson.find(item => { return item.age > 26 })
const index = mudanPerson.findIndex(item => { return item.age > 26 })
console.log(result)
console.log(index)
|
迭代方法
这5个迭代方法都接收两个参数: 以每一项为参数运行的函数,以及可选的作为函数运行上下文的作用域对象(影响函数中this的值)。 每个方法的函数都接收3个参数: 当前数组元素、当前元素索引、数组本身。
1、forEach()
对数组的每一项都运行传入的函数, 无返回值
1 2 3 4 5 6 7 8 9 10
| const arr = ['毛毛', '乐乐', 'jeff', '小罗']
let temp = [] arr.forEach((item,index,arr) => { temp.push({name: item}) }) console.log(temp)
|
2、map()
对数组的每一项都运行传入的函数, 返回由每次函数调用的结果构成的数组。
1 2 3 4 5 6 7 8 9 10
| const arr = ['毛毛', '乐乐', 'jeff', '小罗'] var brr = arr.map((item,index,arr) => { return '名字:' + item; })
console.log(brr)
|
3、filter()
对数组的每一项都运行传入的函数, 函数返回true的项会组成数组返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const person = [ {name: '小罗', age: 24, birthday: 1998}, {name: '毛毛', age: 22, birthday: 2000}, {name: 'Jeff', age: 25, birthday: 1997}, {name: '乐乐', age: 26, birthday: 1996}, {name: '蔡蔡', age: 27, birthday: 1995}, {name: '文婷', age: 24, birthday: 1998}, {name: '烨子', age: 24, birthday: 1998}, {name: '奇奇', age: 27, birthday: 1995}, {name: '团团', age: 22, birthday: 2000}]
const filterArr = person.filter(item => { return item.age <= 24 })
console.log(filterArr)
|
4、every()
对数组的每一项都运行传入的函数, 如果对每一项函数都返回true,则返回true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const mudanPerson = [ {name: '小罗', age: 24, birthday: 1998}, {name: '毛毛', age: 22, birthday: 2000}, {name: 'Jeff', age: 25, birthday: 1997}, {name: '乐乐', age: 26, birthday: 1996}, {name: '蔡蔡', age: 27, birthday: 1995}, {name: '文婷', age: 24, birthday: 1998}, {name: '烨子', age: 24, birthday: 1998}, {name: '奇奇', age: 27, birthday: 1995}, {name: '团团', age: 22, birthday: 2000}]
const result = mudanPerson.every(item => { return item.age >= 22 })
console.log(result)
|
5、some()
对数组的每一项都运行传入的函数, 若有一项函数返回true, 则返回true
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const mudanPerson = [ {name: '小罗', age: 24, birthday: 1998}, {name: '毛毛', age: 22, birthday: 2000}, {name: 'Jeff', age: 25, birthday: 1997}, {name: '乐乐', age: 26, birthday: 1996}, {name: '蔡蔡', age: 27, birthday: 1995}, {name: '文婷', age: 24, birthday: 1998}, {name: '烨子', age: 24, birthday: 1998}, {name: '奇奇', age: 27, birthday: 1995}, {name: '团团', age: 22, birthday: 2000}]
const result = mudanPerson.some(item => { return item.birthday === 1995 })
console.log(result)
|
归并方法
1、reduce()
与 reduceRight()
这两个方法都接受两个参数: 对每一项都会运行的归并函数和可选的归并起点的初始值
归并函数接收4个参数: 上一个归并值、当前项、当前项的索引、数组本身
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const mudanPerson = [ {name: '小罗', age: 24, birthday: 1998}, {name: '毛毛', age: 22, birthday: 2000}, {name: 'Jeff', age: 25, birthday: 1997}, {name: '乐乐', age: 26, birthday: 1996}, {name: '蔡蔡', age: 27, birthday: 1995}, {name: '文婷', age: 24, birthday: 1998}, {name: '烨子', age: 24, birthday: 1998}, {name: '奇奇', age: 27, birthday: 1995}, {name: '团团', age: 22, birthday: 2000}]
const ageTotal = mudanPerson.reduce((total, cur) => { return total + cur.age }, 0)
const ageTotal1 = mudanPerson.reduceRight((total, cur) => { return total + cur.age }, 0)
console.log(ageTotal) console.log(ageTotal1)
|
“拉平”方法
1、flat()
数组的成员有时还是数组,flat()
用于将嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组, 对原数组不改变。
flat()
默认只会“拉平”一层,若想要拉平多层, 可以给flat()传一个整数参数, 表示要拉平的层数。
1 2 3 4 5 6 7 8 9 10
| const arr = [1,2,[3,4, [5,6]]]
const arr1 = arr.flat()
const arr2 = arr.flat(2)
console.log(arr1) console.log(arr2)
|
如果不管多少层嵌套, 都要转成一维数组, 可以用Infinity
关键字作为参数。
1 2 3 4 5
| const arr = [1,[2,[3,[4,[5,6,[7,8]]]]]]
const arr1 = arr.flat(Infinity)
console.log(arr1)
|
如果原数组有空位,flat()
方法会跳过空位。
1 2 3 4
| const arr = [1,2,,4,5]
const arr1 = arr.flat() console.log(arr1)
|
2、flatMap()
flatMap()
方法对原数组的每个成员执行一个函数(相当于执行Array.prototype.map()
),然后对返回值组成的数组执行flat()
方法。该方法返回一个新数组,不改变原数组。
1 2 3 4 5
|
const arr = [2,3,4].flatMap(x => [x, x*2])
console.log(arr)
|
flatMap()
只能展开一层数组
1 2 3 4 5
|
const arr = [1,2,3,4].flatMap(x => [[x*2]])
console.log(arr)
|
flatMap()
方法的参数是一个遍历函数,该函数可以接受三个参数,分别是当前数组成员、当前数组成员的位置(从零开始)、原数组。
1 2 3
| arr.flatMap(function callback(currentValue[, index[, array]]) { }[, thisArg])
|
flatMap()
方法还可以有第二个参数,用来绑定遍历函数里面的this
。