技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTJS

28 个 JavaScript 数组方法:开发者小抄(含现代补充)

所属馆藏
JavaScript
文件格式
Markdown
原始路径
JavaScript/06-28个Javascript数组方法,开发者的小抄
本文目录37 个章节
  1. 1. map()
  2. 2. filter()
  3. 3. reduce()
  4. 4. reduceRight()
  5. 5. fill()
  6. 6. find()
  7. 7. indexOf()
  8. 8. lastIndexOf()
  9. 9. findIndex()
  10. 10. includes()
  11. 11. pop()
  12. 12. push()
  13. 13. shift()
  14. 14. unshift()
  15. 15. splice()
  16. 16. slice()
  17. 17. join()
  18. 18. reverse()
  19. 19. sort()
  20. 20. some()
  21. 21. every()
  22. 22. Array.from()
  23. 23. Array.of()
  24. 24. Array.isArray()
  25. 25. at()
  26. 26. copyWithin()
  27. 27. flat()
  28. 28. flatMap()
  29. 29. 现代补充:findLast() 与 findLastIndex()
  30. 30. 现代补充:toReversed()
  31. 31. 现代补充:toSorted()
  32. 32. 现代补充:toSpliced()
  33. 33. 现代补充:with()
  34. 34. 现代补充:Array.fromAsync()
  35. 三十五、数组方法快速对照表
  36. 使用建议
  37. 参考资料

28 个 JavaScript 数组方法:开发者小抄(含现代补充)

Category(分类): JavaScript Status: 已更新

原文整理了 28 个常用数组方法。本文保留原来的 28 项,并补充近年来已在现代运行环境中可用的 findLasttoSortedtoReversedtoSplicedwithArray.fromAsync()。其中前五项属于 ES2023,Array.fromAsync() 属于 ECMAScript 2026。

先记住三个分类:

  • 不改变原数组mapfiltersliceconcatfindincludestoSorted 等;
  • 改变原数组pushpopshiftunshiftsplicesortreversefillcopyWithin
  • 返回什么:有的返回新数组,有的返回元素/索引/布尔值/字符串/数字或迭代器。

数组方法通常是泛型的,会读取 length 和整数索引;但具体方法对稀疏数组空位的处理不同,不要把空位等同于显式的 undefined

1. map()

对数组中被访问到的每个元素调用回调,返回一个等长的新数组。回调参数依次是元素、索引和原数组:

const numbers = [1, 2, 3, 4]
const doubled = numbers.map((value, index, array) => {
  console.log(index, array === numbers)
  return value * 2
})

console.log(doubled) // [2, 4, 6, 8]

map() 不会改变原数组,但会保留空位;不要用它只做副作用,如果不需要返回数组应使用 for…of

2. filter()

返回通过测试函数的元素组成的新数组:

const even = [1, 2, 3, 4, 5].filter(value => value % 2 === 0)
console.log(even) // [2, 4]

回调返回真值才保留元素。原数组不变,结果数组长度可能小于原数组。

3. reduce()

从左到右把多个元素汇总为一个结果:

const total = [1, 2, 3, 4].reduce((sum, value) => sum + value, 0)
console.log(total) // 10

如果不提供初始值,第一项会作为初始累加器;空数组没有初始值时会抛出 TypeError。复杂对象累加时应提供初始值,避免类型和空数组边界问题。

4. reduceRight()

reduce() 类似,但从右向左处理:

const text = ['a', 'b', 'c'].reduceRight((result, value) => result + value, '')
console.log(text) // cba

它常用于从右侧组合字符串、解析嵌套结构或实现函数组合。

5. fill()

用同一个值填充 [start, end) 范围,会修改原数组

const values = [1, 2, 3, 4, 5]
values.fill(0, 1, 4)
console.log(values) // [1, 0, 0, 0, 5]

如果填充的是对象,所有位置会共享同一个对象引用:

const rows = Array(3).fill({ selected: false })
rows[0].selected = true
console.log(rows[1].selected) // true

需要独立对象时使用 Array.from({ length: 3 }, () => ({ selected: false }))

6. find()

find() 会按索引检查元素,稀疏数组的空位在该回调中可能表现为 undefined;返回第一个通过测试的元素,找不到返回 undefined

const user = [
  { id: 1, name: 'Ada' },
  { id: 2, name: 'Grace' }
].find(item => item.id === 2)

console.log(user?.name) // Grace

它返回元素本身,不是索引。需要索引时使用 findIndex()

7. indexOf()

使用严格相等查找第一个索引,找不到返回 -1

const values = [1, 2, 3, 2]
values.indexOf(2) // 1
values.indexOf(4) // -1
values.indexOf(Number.NaN) // -1

indexOf() 找不到 NaN,需要查找 NaN 时使用 includes()

8. lastIndexOf()

从后向前返回最后一个匹配元素的索引:

const values = [1, 2, 3, 2]
values.lastIndexOf(2) // 3
values.lastIndexOf(2, 2) // 1

第二个参数是开始搜索的索引,会按规范转换并限制在有效范围内。

9. findIndex()

find() 类似,它会按索引检查稀疏数组空位;返回第一个通过测试的索引,找不到返回 -1

const values = [5, 12, 8, 130, 44]
values.findIndex(value => value > 13) // 3

indexOf() 的区别是它接受测试函数,因此可以按对象属性或复杂条件查找。

10. includes()

判断是否包含某个值,使用 SameValueZero:

[1, 2, 3].includes(2) // true
[Number.NaN].includes(Number.NaN) // true
[1, 2, 3].includes(4) // false

第二个参数可指定开始索引:values.includes(2, 2)

11. pop()

删除并返回最后一个元素,会改变数组长度:

const values = [1, 2, 3]
const last = values.pop()
console.log(last, values) // 3 [1, 2]

空数组调用 pop() 返回 undefined

12. push()

把一个或多个元素添加到末尾,返回新长度:

const values = [1, 2]
const length = values.push(3, 4)
console.log(length, values) // 4 [1, 2, 3, 4]

数组长度受安全整数和内存限制,不能把 push 当作无限队列。

13. shift()

删除并返回第一个元素,会改变数组长度:

const values = [1, 2, 3]
const first = values.shift()
console.log(first, values) // 1 [2, 3]

对大型数组频繁 shift() 可能需要移动大量索引;队列可以使用头索引或 Deque 风格结构优化。

14. unshift()

在开头添加一个或多个元素,返回新长度并修改原数组:

const values = [2, 3]
values.unshift(0, 1)
console.log(values) // [0, 1, 2, 3]

同样要注意开头插入的移动成本。

15. splice()

start 开始删除 deleteCount 个元素,并可插入新元素。它会修改原数组,返回被删除元素数组:

const values = [1, 2, 3, 4]
const removed = values.splice(1, 2, 'a', 'b')

console.log(removed) // [2, 3]
console.log(values) // [1, 'a', 'b', 4]

splice(start) 会删除从 start 到末尾的所有元素;splice(start, 0, value) 可用于插入。

16. slice()

返回 [start, end) 的浅拷贝,不修改原数组:

const values = [1, 2, 3, 4]
const part = values.slice(1, 3)
console.log(part, values) // [2, 3] [1, 2, 3, 4]

复制数组常用 values.slice()[...values],但嵌套对象仍共享引用。

17. join()

把数组元素连接为字符串,默认分隔符是逗号:

[1, 2, 3].join(', ') // '1, 2, 3'
['a', 'b', 'c'].join('') // 'abc'
[1, null, undefined].join('-') // '1--'

nullundefinedjoin() 中按空字符串处理。数组嵌套对象会先进行字符串化,不适合作为通用序列化方法。

18. reverse()

原地反转并返回原数组:

const values = [1, 2, 3]
const result = values.reverse()
console.log(values, result === values) // [3, 2, 1] true

需要不改变原数组时使用现代 toReversed()[...values].reverse()

19. sort()

sort() 原地排序并返回原数组。默认按字符串的 UTF-16 码元顺序排序:

[4, 1, 3, 2, 10].sort() // [1, 10, 2, 3, 4]

const numbers = [4, 1, 3, 2, 10]
numbers.sort((a, b) => a - b)
console.log(numbers) // [1, 2, 3, 4, 10]

ES2019 起规范要求排序稳定,但比较函数仍应保持一致的比较关系。比较函数返回负数表示 a 在前,正数表示 b 在前,零表示顺序相同。

需要保留原数组时使用 toSorted()

20. some()

只要至少一个元素通过测试就返回 true,会短路:

[1, 3, 5, 8].some(value => value % 2 === 0) // true

空数组调用 some() 返回 false

21. every()

只有所有元素通过测试才返回 true,会短路:

[2, 4, 6].every(value => value % 2 === 0) // true
[2, 3, 6].every(value => value % 2 === 0) // false

空数组调用 every() 返回 true,这是逻辑上的“全称命题对空集合成立”,使用时要注意业务语义。

22. Array.from()

把可迭代对象或类数组对象转换成新数组,可以传映射函数:

Array.from('abc') // ['a', 'b', 'c']
Array.from(new Set([1, 1, 2])) // [1, 2]
Array.from({ length: 3 }, (_, index) => index + 1) // [1, 2, 3]

它与展开语法不同:Array.from() 可以处理具有 length 的类数组对象,并能直接接收映射回调。

23. Array.of()

无论参数数量和类型如何,都把参数作为数组元素:

Array.of(7) // [7]
Array.of(1, 2, 3) // [1, 2, 3]
Array(7) // 长度为 7 的稀疏数组
Array(1, 2, 3) // [1, 2, 3]

24. Array.isArray()

可靠判断一个值是否为数组,包括跨 realm 场景:

Array.isArray([]) // true
Array.isArray({}) // false
Array.isArray(new Array(3)) // true

不要使用 value instanceof Array 代替它来判断来自其他窗口的数组。

25. at()

按整数索引读取元素,支持负索引,不修改数组:

const values = [10, 20, 30]
values.at(0) // 10
values.at(-1) // 30
values.at(-4) // undefined

它也适用于字符串和 TypedArray 的相应方法。

26. copyWithin()

把数组的一段浅复制到同一个数组的另一个位置,修改元素但不改变长度:

const values = [1, 2, 3, 4, 5]
values.copyWithin(0, 3, 5)
console.log(values) // [4, 5, 3, 4, 5]

参数是 targetstartend,区间仍然是左闭右开。

27. flat()

按指定深度展开嵌套数组,返回新数组,默认深度为 1:

[1, 2, [3, 4], [5, [6]]].flat() // [1, 2, 3, 4, 5, [6]]
[1, 2, [3, 4], [5, [6]]].flat(Infinity) // [1, 2, 3, 4, 5, 6]

flat() 会在展开过程中移除被展开层级中的数组空位。它只展开数组,不会把普通对象当作数组展开。

28. flatMap()

先对每个元素映射,再把结果按深度 1 展开,适合一对多转换或过滤:

[1, 2, 3].flatMap(value => [value, value * 10])
// [1, 10, 2, 20, 3, 30]

[1, 2, 3, 4].flatMap(value => value % 2 ? [value] : [])
// [1, 3]

flatMap() 只展开一层,不能用它替代任意深度的 flat(Infinity)

29. 现代补充:findLast()findLastIndex()

ES2023 从数组末尾开始查找:

const logs = [
  { level: 'info' },
  { level: 'error' },
  { level: 'info' }
]

logs.findLast(log => log.level === 'error') // { level: 'error' }
logs.findLastIndex(log => log.level === 'error') // 1

30. 现代补充:toReversed()

返回反转后的新数组,不修改原数组:

const values = [1, 2, 3]
const reversed = values.toReversed()
console.log(values, reversed) // [1, 2, 3] [3, 2, 1]

31. 现代补充:toSorted()

返回排序后的新数组:

const values = [10, 2, 1]
const sorted = values.toSorted((a, b) => a - b)
console.log(values, sorted) // [10, 2, 1] [1, 2, 10]

32. 现代补充:toSpliced()

返回执行 splice 效果后的新数组,不修改原数组:

const values = [1, 2, 3, 4]
const next = values.toSpliced(1, 2, 'a', 'b')
console.log(values, next) // [1, 2, 3, 4] [1, 'a', 'b', 4]

33. 现代补充:with()

返回把某个索引替换后的新数组,支持负索引:

const values = ['a', 'b', 'c']
const next = values.with(-1, 'z')
console.log(values, next) // ['a', 'b', 'c'] ['a', 'b', 'z']

索引超出范围会抛出 RangeError,与直接访问不存在索引不同。

34. 现代补充:Array.fromAsync()

Array.fromAsync()(ECMAScript 2026)异步收集异步可迭代对象、可迭代对象或类数组对象中的值,并返回 Promise:

async function example() {
  const values = await Array.fromAsync([
    Promise.resolve(1),
    Promise.resolve(2),
    3
  ])

  console.log(values) // [1, 2, 3]
}

它适合异步迭代和逐项收集,不能把它理解成一定会并发执行所有异步任务;需要并发控制时应明确使用 Promise.all()、队列或限流器。

三十五、数组方法快速对照表

方法返回值是否修改原数组
map新数组
filter新数组
reduce / reduceRight累加结果
find / findLast元素或 undefined
findIndex / findLastIndex索引或 -1
some / every / includes布尔值
slice / flat / flatMap新数组
toSorted / toReversed / toSpliced / with新数组
from / of / fromAsync新数组或 Promise不适用
push / unshift新长度
pop / shift删除的元素
splice删除的元素数组
sort / reverse原数组
fill / copyWithin原数组
join字符串

使用建议

  1. 先确认要不要修改原数组;状态管理和并发代码优先使用不可变方法;
  2. 数值排序显式传入 (a, b) => a - b
  3. reduce() 尽量提供正确的初始值;
  4. 查找 NaN 使用 includes(),查找复杂条件使用 find()
  5. 大数组上的 shift()unshift()、频繁 splice() 需要关注移动成本;
  6. 回调中的异步操作不要误以为 map() 会等待,使用 Promise.all(values.map(...))
  7. Array.fromAsync()、不可变数组方法和迭代器方法要根据目标浏览器/Node 版本做兼容性验证;MDN 的 Baseline 时间不等同于 ECMAScript 标准发布年份。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS