15 个常用的 JavaScript 数组操作
数组是 JavaScript 中普遍使用的数据结构。
你可以在数组上执行许多操作(迭代,插入元素,删除元素,等等)。数组对象提供了许多像 array.forEach()
,array.map()
这样实用的的方法。
我经常发现自己对数组可能的操作和相应的实现感到不知所措。您可能也处于相同的情况。
我决定实现数组的 15 个常用的操作。如果你需要执行特定操作,仅需要从目录中选择其实现。
目录: [[toc]]
迭代
for…of 循环
for(const item of items)
循环迭代数组项目。让我们迭代 colors
列表:
const colors = ['blue', 'green', 'white']
for (const color of colors) {
console.log(color)
}
// 'blue'
// 'green'
// 'white'
在每一个迭代项,迭代的元素被分配给变量 color
。
提示:
- 你可以在任何一次的迭代中使用
break
声明中断循环。
for 循环
for(let i; i < array.length; i++)
使用增值索引变量循环迭代数组元素。
for
通常必须在每次循环时使用增值 index
变量:
const colors = ['blue', 'green', 'white']
for (let index = 0; index < colors.length; index++) {
const color = colors[index]
console.log(color)
}
// 'blue'
// 'green'
// 'white'
index
变量从 0
到 colors.length - 1
增加。该变量被用于访问数组的元素:colors[index]
。
提示:
- 你可以在任何一次的迭代中使用
break
声明中断循环。
array.forEach() 方法
array.forEach()
方法调用 callback
回调函数迭代数组的每一项。
每一次的迭代中,callback(item [, index [, array]])
回调函数与参数(迭代项,索引,数组自身)一起执行:
const colors = ['blue', 'green', 'white']
colors.forEach((value, index) => {
console.log(value, index)
})
// 'blue', 0
// 'green', 1
// 'white', 2
array.forEach(callback)
调用 callback
访问数组的项目 3 次:'blue'
, 'green'
, 'white'
。
提示:
- 我们不能中断
array.forEach()
迭代。
Map
array.map() 方法
array.map(callback)
方法通过 callback
回调函数迭代数组的每一项的返回值创建一个新数组。
在 callback(item[, index[, array]])
的每一次迭代都会引用参数:当前项,索引和数组自身。回调函数应该返回一个新元素。
让我们增值数组的元素:
const numbers = [0, 2, 4]
const newNumbers = numbers.map((number) => {
return number + 1
})
newNumbers // => [1, 3, 5]
numbers.map(increment)
通过增值 numbers
数组的每一项创建一个新数组。
提示:
array.map
创建一个新的映射数组,没有修改原数组。
Array.from() 函数
Array.from(arrayLike[, callback])
方法通过使用 callback
回调函数返回值最为数组项创建一个新数组。
每次迭代 callback(item[, index[, array]])
提供参数:当前项,索引和数组自身。它应该返回新项。
让我们增值一个数组:
const numbers = [0, 2, 4]
const newNumbers = Array.from(numbers, (number) => {
return number + 1
})
newNumbers // => [1, 3, 5]
Array.from(numbers, increment)
通过增值数组的每一项创建一个新数组。
提示:
Array.from
创建一个新的映射数组,不会修改原数组。Array.from
擅长用于映射类数组对象
Reduce
array.reduce() 方法
array.reduce(callback[, initialValue])
通过 callback
回调函数作为 reducer 缩短数组为一个值。
每次迭代 callback(accumulator, item[, index[, array]])
被调用,同时调用参数:累加值,当前项,索引和数组自身。回调函数应该返回该累加值。
下面的例子对数组的项求和:
const numbers = [2, 0, 4]
function summarize(accumulator, number) {
return accumulator + number
}
const sum = numbers.reduce(summarize, 0)
sum // => 6
在第一步 accumulator
被初始为 0
。然后 summarize
函数被数组的每一项调用累加为数组项的和。
提示:
- 如果你没有设置
initialValue
,数组的第一项会成为初始值。
Concat
array.concat() 方法
array.concat(array1[, array2, ...])
连接原数组一个或多个数组。
让我们连接两个包含名称的数组:
const heroes = ['Batman', 'Robin']
const villains = ['Joker', 'Bane']
const everyone = heroes.concat(villains)
everyone // => ['Batman', 'Robin', 'Joker', 'Bane']
heroes.concat(villains)
通过连接数组 heroes
和 villains
创建一个新数组。
提示:
array.concat()
创建了一个新数组,没有修改原数组array.concat(array1[, array2, ...])
接受多个数组连接。
扩展操作符(spread operator)
你可以在数组字面量中使用扩展操作符连接数组:[...array1, ...array2]
。
让我们连接两个包含名称的数组:
const heroes = ['Batman', 'Catwoman']
const villains = ['Joker', 'Bane']
const names = [...heroes, ...villains]
names // => ['Batman', 'Catwoman', 'Joker', 'Bane']
[...heroes, ...villains]
展开数组 heroes
和 villains
的项,然后创建一个新数组包含所有的扩展项。
[...arr1, ...arr2, ...arrN]
:你可以使用扩展操作符连接你需要的任意数量的数组
Slice
array.slice() 方法
array.slice([fromIndex[, toIndex]])
返回数组从索引 fromIndex
开始且结束于 toIndex
(不包含 toIndex
自身)的部分。fromIndex
可选参数默认为 0
,toIndex
可选参数的默认值为 array.length
让我们获取一些数组切片:
const names = ['Batman', 'Catwoman', 'Joker', 'Bane']
const heroes = names.slice(0, 2)
const villains = names.slice(2)
heroes // => ['Batman', 'Catwoman']
villains // => ['Joker', 'Bane']
names.slice(0, 2)
返回数组 names
前两项。names.slice(2)
返回数组索引 2 开始,end
参数默认为 array.length
。
提示:
array.slice()
创建一个新数组,没有修改原数组。
克隆
扩展操作符(spread operator)
一个简单克隆数组的方式是使用扩展操作符:const clone = [...array]
;
让我们克隆数组 colors
:
const colors = ['white', 'black', 'gray']
const clone = [...colors]
clone // => ['white', 'black', 'gray']
colors === clone // => false
[...colors]
创建了数组 colors
的克隆数组。
提示:
[...array]
创建的是浅克隆数组。
array.concat() 方法
[].concat(array)
是另一个克隆数组的方式。
const colors = ['white', 'black', 'gray']
const clone = [].concat(colors)
clone // => ['white', 'black', 'gray']
colors === clone // => false
[].concat(colors)
创建了数组 colors
的克隆数组。
提示:
[].concat(array)
创建的是浅克隆数组。
array.slice() 方法
array.slice()
是另一个克隆数组的方式。
const colors = ['white', 'black', 'gray']
const clone = colors.slice()
clone // => ['white', 'black', 'gray']
colors === clone // => false
colors.slice()
创建了数组 colors
的克隆数组。
提示:
[].slice()
创建的是浅克隆数组。
检索
array.includes() 方法
array.includes(itemToSearch[, fromIndex])
返回一个布尔值,确认数组 array
是否包含 itemToSearch
。可选参数 fromIndex
默认值为 0
,用于指定开始检索的索引。
让我们确认数组项中是否存在 2
和 99
:
const numbers = [1, 2, 3, 4, 5]
numbers.includes(2) // => true
numbers.includes(99) // => false
numbers.includes(2)
返回 true
,因为 2
存在于 numbers
数组。
numbers.includes(99)
相反返回 false
,因为 numbers
数组不包含 99
。
array.find() 方法
array.find(predicate)
方法返回第一个满足 predicate
函数条件的数组项。
每一次迭代 predicate(item[, index[, array]])
函数被调用,其参数为:迭代项,索引和数组自身。
举例来说,让我们找到第一个偶数:
const numbers = [1, 2, 3, 4, 5]
function isEven(number) {
return number % 2 === 0
}
const evenNumber = numbers.find(isEven)
evenNumber // => 2
numbers.find(isEven)
返回 numbers
中第一个偶数,它是 2
。
提示:
- 如果没有满足 predicate 函数的项,
array.find()
返回undefined
。
array.indexOf() 方法
array.indexOf(itemToSearch[, fromIndex])
返回 array
中第一次出现 itemToSearch
的索引。默认值为 0
的可选参数 fromIndex
是指定开始检索的索引。
让我们找到 'Joker'
的位置:
const names = ['Batman', 'Catwoman', 'Joker', 'Bane']
const index = names.indexOf('Joker')
index // => 2
'Joker'
在 names
中的索引位置是 2
。
提示:
- 如果没有找到数组项,
array.indexOf(itemToSearch)
返回-1
。array.findIndex(predicate)
可以替换该方法找到索引位置,它使用 predicate 函数确定位置。
查询(query)
array.every() 方法
如果数组的每项都通过 predicate
的检查,array.every(predicate)
方法将返回 true
。
每次迭代 predicate(item[, index[, array]])
断言函数被调用,其参数为:迭代项,索引和数组自身。
让我们查明数组 evens
和 numbers
是否仅包含偶数:
const evens = [0, 2, 4, 6]
const numbers = [0, 1, 4, 6]
function isEven(number) {
return number % 2 === 0
}
evens.every(isEven) // => true
numbers.every(isEven) // => false
evens.every(isEven)
返回 true
,因为 evens
的所有项都是偶数。
然而,numbers.every(isEven)
的值是 false
,因为 numbers
包含一个奇数 1
。
array.some() 方法
如果只要数组有一项通过 predicate
的检查,array.some(predicate)
方法返回 true
。
每次迭代 predicate(item[, index[, array]])
函数被调用,其参数为:迭代项,索引和数组自身。
让我们查明数组是否包含偶数:
const numbers = [1, 5, 7, 10]
const odds = [1, 3, 3, 3]
function isEven(number) {
return number % 2 === 0
}
numbers.some(isEven) // => true
odds.some(isEven) // => false
numbers.some(isEven)
返回 true
,因为数组 numbers
中存在偶数项 10
。
但是 odds.some(isEven)
返回 false
,因为数组 odds
仅仅包含奇数。
过滤(filter)
array.filter()
array.filter(predicate)
方法返回一个包含通过 predicate
函数检查的元素项的新数组。
每次迭代 predicate(item[, index[, array]])
被调用,其参数为:迭代项,索引和数组自身。
让我们过滤数组使其仅包含偶数:
const numbers = [1, 5, 7, 10]
function isEven(number) {
return number % 2 === 0
}
const evens = numbers.filter(isEven)
evens // => [10]
numbers.filter(isEven)
通过过滤 numbers
中包含的偶数创建一个新数组。
提示:
array.filter()
创建一个新数组,没有修改原数组。
插入(insert)
array.push() 方法
array.push(item1[..., itemN])
方法添加一个或多个元素项到数组的末尾,并返回数组的新长度。
让我们添加 'Joker'
到数组 names
的结尾:
const names = ['Batman']
names.push('Joker')
names // ['Batman', 'Joker']
names.push('Joker')
插入新的元素 'Joker'
到数组 names
的结尾。
提示:
array.push()
修改了原数组。array.push(item1, item2, ..., itemN)
可以添加多个元素项。
array.unshift() 方法
array.unshift(item1[..., itemN])
方法添加一个或多个元素项到数组的开头,并返回数组的新长度。
让我们添加 'Catwoman'
到数组 names
的开头:
const names = ['Batman']
names.unshift('Catwoman')
names // ['Catwoman', 'Batman']
names.unshift('Catwoman')
插入新项 'Catwoman'
到数组 names
的开头。
提示:
array.unshift()
修改了原数组。array.unshift(item1, item2, ..., itemN)
可以插入多个元素项。
扩展操作符(spread operator)
你可以通过组合扩展操作符和数组字面量以不可变的方式插入元素项到数组。
添加一个元素到数组的结尾:
const names = ['Joker', 'Bane']
const names2 = [...names, 'Batman']
names2 // => ['Joker', 'Bane', 'Batman'];
添加一个元素到数组的开始:
const names = ['Joker', 'Bane']
const names2 = ['Batman', ...names]
names2 // => ['Batman', 'Joker', 'Bane'];
添加一个元素项到数组的任意位置:
const names = ['Joker', 'Bane']
const indexToInsert = 1
const names2 = [
...names.slice(0, indexToInsert),
'Batman',
...names.slice(indexToInsert),
]
names2 // => ['Joker', 'Batman', 'Bane'];
删除(remove)
array.pop() 方法
array.pop()
方法删除数组的最后一项,然后让回删除的那一项。
举例来说,人我们删除数组 colors
的最后一项:
const colors = ['blue', 'green', 'black']
const lastColor = colors.pop()
lastColor // => 'black'
colors // => ['blue', 'green']
colors.pop()
删除 colors
的最后一个元素并返回了它。
提示:
array.pop()
修改了原数组。
array.shift() 方法
array.shift()
方法删除数组的第一项,然后返回这一项。
举例来说,让我们删除数组 colors
的第一个元素项:
const colors = ['blue', 'green', 'black']
const firstColor = colors.shift()
firstColor // => 'blue'
colors // => ['green', 'black']
colors.shift()
删除了数组 colors
的第一个元素项 'blue'
并返回它。
提示:
array.shift()
修改了原数组。array.shift()
的复杂度为 O(n)。
array.splice() 方法
array.splice(fromIndex[, removeCount[, item1[, item2[, ...]]]])
删除数组的元素项并使用新的元素项替换删除项。
举例来说,让我们删除数组从索引 1
开始的 2 项:
const names = ['Batman', 'Catwoman', 'Joker', 'Bane']
names.splice(1, 2)
names // => ['Batman', 'Bane']
names.splice(1, 2)
删除了 'Catwoman'
和 'Joker'
元素项。
names.splice
可以插入新项到移除的位置。让我们替换从索引 1
开始的 2 项,并插入新的元素项 'Alfred'
:
const names = ['Batman', 'Catwoman', 'Joker', 'Bane']
names.splice(1, 2, 'Alfred')
names // => ['Batman', 'Alfred' ,'Bane']
提示:
array.shift()
修改了原数组。
扩展操作符(spread operator)
你可以通过组合扩展操作符和数组字面量以不可变的方式删除数组的元素。
让我们删除一些元素项:
const names = ['Batman', 'Catwoman', 'Joker', 'Bane']
const fromIndex = 1
const removeCount = 2
const newNames = [
...names.slice(0, fromIndex),
...names.slice(fromIndex + removeCount),
]
newNames // => ['Batman', 'Bane']
newNames
包含 names
的元素项,但是没有的 2 项被移除。
使空白(empty)
array.length
array.length
是一个包含数组长度的属性。更多的是,array.length
是可写的。
如果你写一个小于当前长度值 array.length = newLength
,数组的多余元素项将被删除。
让我们使用 array.length = 0
来删除数组的所有元素项:
const colors = ['blue', 'green', 'black']
colors.length = 0
colors // []
array.splice() 方法
array.splice(fromIndex[, removeCount[, item1[, item2[, ...]]]])
删除数组元素项并插入新的替换项。
如果 removeCount
参数缺失,然后 array.splice()
删除数组从 fromIndex
开始的所有元素项。
让我们使用该方法删除数组的所有元素:
const colors = ['blue', 'green', 'black']
colors.splice(0)
colors // []
colors.splice(0)
删除了数组 colors
的所有元素。
填充(fill)
array,fill() 方法
array.fill(value[, fromIndex[, toIndex]])
使用 value
从索引 fromIndex
到 toIndex
(除了 toIndex
自身)填充数组。可选参数 fromIndex
的默认值为 0
,可选参数 toIndex
的默认值为 array.length
。
举例来说,让我们使用零填充数组:
const numbers = [1, 2, 3, 4]
numbers.fill(0)
numbers // => [0, 0, 0, 0]
numbers.fill(0)
使用零填充了数组。
你可以初始化特定长度的数组并使用 Array(length).fill(initial)
初始值。
const length = 3
const zeros = Array(length).fill(0)
zeros // [0, 0, 0]
Array(length).fill(0)
创建了包含 3 个零的数组。
提示:
array.shift()
修改了原数组。
Array.from 函数
Array.from()
可以用于从确定长度的对象初始化为数组:
const length = 4
const emptyObjects = Array.from({ length }, () => {
return {}
})
emptyObjects // [{}, {}, {}, {}]
emptyObjects
使用不同实例的空对象初始化数组。
降维(flatten)
array.flat() 方法
array.flat([depth])
方法通过递归降维元素是数组的项来创建数组,直到降维到确认深度 depth
。可选参数 depth
默认值为 1
。
让我们降维数组:
const arrays = [0, [1, 3, 5], [2, 4, 6]]
const flatArray = arrays.flat()
flatArray // [0, 1, 3, 5, 2, 4, 6]
arrays
包含数字和数字数组的混合。arrays.flat()
展平了数组,于是该数组只包含数字。
提示:
array.filter()
创建一个新数组,没有修改原数组。
排序(sort)
array.sort([compare])
方法排序数组的元素项。
可选参数 compare(item1, item2)
是自定义元素顺序的回调函数。如果 compare(item1, item2)
返回是:
-1
,数组排序中item1
将在item2
的后面。1
,数组排序中item2
将在item1
的后面。0
, 元素项的位置不会改变。
让我们排序数字数组:
const numbers = [4, 3, 1, 2]
numbers.sort()
numbers // => [1, 2, 3, 4]
numbbers.sort()
以增序顺序排序。
让我们使用对比函数使偶数在奇数的前面:
const numbers = [4, 3, 1, 2]
function compare(n1, n2) {
if (n1 % 2 === 0 && n2 % 2 !== 0) {
return -1
}
if (n1 % 2 !== 0 && n2 % 2 === 0) {
return -1
}
return 0
}
numbers.sort(compare)
numbers // => [4, 2, 3, 1]
numbers.sort(compare)
使用自定义对比函数将偶数排在前面。
提示:
array.shift()
修改了原数组。
本文由 吳文俊 翻译,原文地址 15 Common Operations on Arrays in JavaScript (Cheatsheet)