前言
下面的知识点大多来自 [MDN](Array - JavaScript | MDN (mozilla.org))
理解数组
数组:一种将一组数据有序的存储在单个变量名下的优雅方式。
在 JavaScript 中,数组不属于基本类型,而是一个对象,一个名叫 Array 的对象。
数组与传统对象的区别在于其数据结构和访问方式不同。
下面是数组的一些核心特征。
-
可调整大小,并且可以包含不同的数据类型。
-
非关联数据,因此不可使用任意字符串作为索引访问数组元素,必须使用负整数作为索引访问。负整数的字符串形式也可以访问,内部会隐式通过 toString() 方法将 "5" 转成 5 来作为索引。
-
数组索引的值从 0 开始,最后一个索引是数组的 length 属性减去 1 的值。
-
数组的复制操作创建浅拷贝。所有的 JavaScript 对象的标准内置复制操作都会创建浅拷贝而不是深拷贝。
数组的length属性
length 属性是数组的实例属性,表示数组中元素的个数,length 数值总是大于数组的最大索引。
若设置 length 值超过数组索引的最大值时会对数组填充 [空槽](索引集合类 - JavaScript | MDN (mozilla.org))
若设置 length 小于数组索引时会将超出的元素删除。
关于数组中一些方法和空槽的关联:developer.mozilla.org/zh-CN/docs/…
如果想要删除数组的最后一个元素的话可以这么做
const arr = [1, 2, 3]
arr.length = 2
还有两种方式是:
const arr = [1, 2, 3]
arr.splice(-1) // splice()方法可以删除指定位置的元素,如果省略第二个参数,则会删除从指定位置到数组末尾的所有元素。
const a = arr.pop() // pop()方法会删除数组的最后一个元素,并返回被删除的元素。
在性能方面,pop() 方法是最好的选择。
splice() 方法和直接修改 length 属性的方式,都需要遍历数组来删除元素,可能会导致性能下降,特别是对于较大的数组。
而 pop() 方法只需删除最后一个元素,不会涉及遍历其他元素,所以它是更优的选择。
创建和获取数组
创建数组
数组是一个对象,我们理应使用其构造函数来创建
const arr = new Array(3)
const arr2 = new Array("a", "b")
但实际上我们经常使用数组字面量的方式创建数组,这样更便捷。
const arr = [1, 2, "3"]
Array.isArray()
判断值是否是数组,返回一个布尔值。
获取数组
通过我们可以通过 括号表示法 获取数组
const arr = [1, 2, "3"]
arr[1] // 2
也可以用数组的 at() 方法获取数组
const arr = [1, 2, "3"]
arr.at(1) // 2
区别在于当传入负数的时候,括号表示法就不能支持了。
const arr = [1, 2, "3"]
arr[arr.length - 1] // X
arr.at(-1) // '3'
常用的数组方法
1. 增加数组元素
Array.prototype.push()
push() 方法将指定的元素添加到数组的末尾,同时修改数组的 length 属性,最终返回修改后的 length。
const arr = [1, 2, "3"]
const arrL = arr.push("4") // 4
// 合并数组,注意不会处理相同的元素
const arr2 = [2, 3, "4"]
arr.push(...arr2) // 7
Array.prototype.concat()
concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
const arr = [1, 2, "3"]
const arr2 = arr.concat("4") // [1, 2, '3', '4']
Array.prototype.unshift()
unshift() 方法将指定元素添加到数组的开头,用法同 push() 一样。
若想返回新数组,可以用 Array.prototype.toSpliced() 实现
2. 删除数组元素
Array.prototype.slice()
slice() 方法用于截取数组,方法返回一个新的数组对象,原始数组不会被改变。
方法的第一个参数表示从哪里开始,第二个参数表示到哪里结束
若第一个参数是负数则从数组末尾开始计算
第二个参数若不传则一直截取到数组末尾
const arr = [1, 2, "3"]
const arr2 = arr.slice(1, 3) // [2, "3"]
Array.prototype.pop()
pop() 方法从数组中删除最后一个元素,并返回该元素的值。此方法会更改数组的长度。
const arr = [1, 2, "3"]
arr.pop() // '3'
const arr2 = arr.slice(0, -1) // 这样也能实现删除数组最后一个元素,但会返回一个数组
Array.prototype.shift()
shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
const arr = [1, 2, "3"]
arr.shift() // 1
const arr2 = arr.slice(1) // 这样也可以删除数组第一个元素,但会返回一个数组
3. 改变数组顺序
Array.prototype.reverse()
reverse() 方法就地反转数组中的元素,返回同一数组的引用。
const arr = [1, 2, "3"]
const arr2 = arr.reverse() // ['3', 2, 1] 注意 arr也变成了 ['3', 2, 1]
要在不改变原始数组的情况下反转数组中的元素,使用 toReversed()。
Array.prototype.sort()
跟 reverse() 方法类似,也是就地修改数组元素,返回同一数组的引用。区别在于 sort 是按照一定的顺序重新排列,默认会将元素转成字符串,按照其 UTF-16 码元值升序排列。
const arr = [1, 3, "2"]
const arr2 = arr.sort() // 注意 arr也变成了 [1, '2', 3]
可以在方法中传入一个实现排序顺序的函数。
如果想要不改变原数组的排序方法,可以使用 toSorted()。
4. 迭代数组
Array.prototype.forEach()
forEach() 方法对数组的每个元素执行一次给定的函数。
const arr = [1, 3, "2"]
arr.forEach(a => console.log(a))
Array.prototype.map()
map() 方法创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。
const arr = [1, 3, "2"]
const arr2 = arr.map(a => a + 1) // [2, 4, '21']
map() 方法常用于需要重新格式化数组中的对象的时候
Array.prototype.filter()
filter() 方法创建一个新数组,这个新数组包含通过所提供函数实现的测试的所有元素。也就是说会过滤掉不符合条件的元素。
const arr = [1, 3, "2"]
const arr2 = arr.filter(a => a > 2) // [3]
filter() 方法可以用来过滤数组,如根据搜索条件过滤数组内容等
Array.prototype.every()
every() 方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。
const arr = [1, 3, "2"]
const verify = arr.every(a => a > 2) // false
可以用来检查所有数组元素的大小和检查数组是否是另一个数组的子集
Array.prototype.some()
some() 方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。返回一个布尔值。
与 every() 方法的区别是 every 检查所有元素,而 some() 方法找到匹配的就返回 true 了。
const arr = [1, 3, "2"]
const verify = arr.some(a => a > 2) // true
可以用来测试数组元素的值、判断数组元素中是否存在某个值
如果只是判断数组元素是否存在某个值可以使用 includes() 方法
const arr = [1, 3, "2"]
const verify = arr.includes(2) // true
Array.prototype.find()
find() 方法返回数组中满足提供的测试函数的第一个元素的值,若没找到则返回 undefined。
const arr = [1, 3, "2"]
const val = arr.find(a => a > 2) // 3
find() 方法正序迭代数组,findLast() 则是反向迭代数组。
如果需要查找某个值的索引可以使用 findIndex() 方法
const arr = [1, 3, "2"]
const index = arr.findIndex(a => a > 2) // 1
findLastIndex() 反向迭代数组查找某个值的索引
5. 其他常用数组方法
Array.prototype.join()
将给定数组或类数组对象所有元素连接成一个字符串,如果只有一个元素那么就直接返回这个元素。
const arr = [1, 3, "2"]
const str = arr.join() // '1,3,2'
若只是需要按照逗号来做分隔符的话,那么直接使用原型链上 Function 的 toString() 方法就好了
Array.prototype.reduce()
reduce() 方法对数组中每个元素都按序执行一个给定的函数,每次运行这个给定函数会先将计算结果作为参数传入,最后返回一个总结果。
下面是 MDN 上的一个计算数组所有元素总和的例子
const array1 = [1, 2, 3, 4];
// 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue
);
console.log(sumWithInitial);
// Expected output: 10
在实际项目中可以用来按对象中的属性名称来对数组进行分组,如果使用 filter() 和 map() 两个方法的话会遍历数组两次,而 reduce() 方法只用遍历一次数组。
reduce() 也可以用来去重,但实际上通过 Set 和 Array.from() 实现去重性能更好。
6. 其他有意思的实验性的数组方法
Array.prototype.group()
group() 方法可以将给定数组按字符串值进行分类,如果需要使用任意值作为键的话,可以使用 groupToMap() 方法。
目前这两个方法仅在 Safari 16.2 / Safari 16.4 上实现了,目前还无法使用。