•  阅读 9 分钟

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 变量从 0colors.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) 通过连接数组 heroesvillains 创建一个新数组。

提示:

  • 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] 展开数组 heroesvillains 的项,然后创建一个新数组包含所有的扩展项。

  • [...arr1, ...arr2, ...arrN]:你可以使用扩展操作符连接你需要的任意数量的数组

Slice

array.slice() 方法

array.slice([fromIndex[, toIndex]]) 返回数组从索引 fromIndex 开始且结束于 toIndex(不包含 toIndex 自身)的部分。fromIndex 可选参数默认为 0toIndex 可选参数的默认值为 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,用于指定开始检索的索引。

让我们确认数组项中是否存在 299

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]]) 断言函数被调用,其参数为:迭代项,索引和数组自身。

让我们查明数组 evensnumbers 是否仅包含偶数:

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 从索引 fromIndextoIndex(除了 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)

> cd ..