Skip to content

数组扩展方法

ES6 为数组新增了许多实用方法,让数组操作更加便捷。

Array.from()#

将类数组或可迭代对象转为真正的数组。

基本用法#

// 类数组对象
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
Array.from(arrayLike) // ['a', 'b', 'c']
// 字符串
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
// Set
Array.from(new Set([1, 2, 2, 3])) // [1, 2, 3]
// Map
Array.from(
new Map([
['a', 1],
['b', 2],
])
) // [['a', 1], ['b', 2]]
// NodeList
const divs = document.querySelectorAll('div')
Array.from(divs) // [div, div, div, ...]

映射函数#

第二个参数是映射函数,类似 map

Array.from([1, 2, 3], (x) => x * 2) // [2, 4, 6]
// 等价于
Array.from([1, 2, 3]).map((x) => x * 2)
// 生成数字序列
Array.from({ length: 5 }, (_, i) => i) // [0, 1, 2, 3, 4]
Array.from({ length: 5 }, (_, i) => i + 1) // [1, 2, 3, 4, 5]
// 生成随机数组
Array.from({ length: 5 }, () => Math.random())

实际应用#

// 数组去重
function unique(arr) {
return Array.from(new Set(arr))
}
unique([1, 2, 2, 3, 3, 3]) // [1, 2, 3]
// 创建二维数组
function create2DArray(rows, cols, value = 0) {
return Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => value)
)
}
create2DArray(3, 4, 0)
// [[0,0,0,0], [0,0,0,0], [0,0,0,0]]
// 生成字母表
const alphabet = Array.from({ length: 26 }, (_, i) =>
String.fromCharCode(65 + i)
)
// ['A', 'B', 'C', ..., 'Z']
// Unicode 字符正确处理
Array.from('𠮷') // ['𠮷'](正确处理 32 位字符)
'𠮷'.split('') // ['\uD842', '\uDFB7'](错误)

Array.of()#

创建包含指定元素的数组,解决 new Array() 的怪异行为:

// new Array 的问题
new Array(3) // [empty × 3](单个数字创建指定长度的空数组)
new Array(3, 4) // [3, 4]
new Array('3') // ['3']
// Array.of 行为一致
Array.of(3) // [3]
Array.of(3, 4) // [3, 4]
Array.of('3') // ['3']
Array.of(undefined) // [undefined]
Array.of() // []

find() 和 findIndex()#

查找符合条件的元素或索引:

const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 3, name: '王五' },
]
// find 返回元素
const user = users.find((u) => u.id === 2)
console.log(user) // { id: 2, name: '李四' }
// 找不到返回 undefined
users.find((u) => u.id === 100) // undefined
// findIndex 返回索引
users.findIndex((u) => u.id === 2) // 1
// 找不到返回 -1
users.findIndex((u) => u.id === 100) // -1

indexOf 的区别:

// indexOf 使用 === 比较,无法查找 NaN
;[NaN].indexOf(NaN) // -1
// find 可以使用自定义条件
;[NaN].find((x) => Number.isNaN(x)) // NaN
;[NaN].findIndex((x) => Number.isNaN(x)) // 0
// indexOf 只能查找值,find 可以查找对象属性
const arr = [{ id: 1 }, { id: 2 }]
arr.indexOf({ id: 1 }) // -1(对象引用不同)
arr.find((item) => item.id === 1) // { id: 1 }

findLast() 和 findLastIndex()#

ES2023 新增,从数组末尾开始查找:

const numbers = [1, 2, 3, 2, 1]
// 从前往后找第一个
numbers.find((n) => n === 2) // 2(索引 1)
numbers.findIndex((n) => n === 2) // 1
// 从后往前找第一个
numbers.findLast((n) => n === 2) // 2(索引 3)
numbers.findLastIndex((n) => n === 2) // 3
// 实际应用:找最后一个满足条件的元素
const logs = [
{ time: '10:00', type: 'info' },
{ time: '10:05', type: 'error' },
{ time: '10:10', type: 'info' },
{ time: '10:15', type: 'error' },
]
logs.findLast((log) => log.type === 'error')
// { time: '10:15', type: 'error' }

fill()#

用固定值填充数组:

// 基本用法
;[1, 2, 3].fill(0) // [0, 0, 0]
// 指定起始和结束位置
;[1, 2, 3, 4, 5].fill(0, 1, 3) // [1, 0, 0, 4, 5]
// 创建并填充
new Array(5).fill(0) // [0, 0, 0, 0, 0]
// 🔶 注意:对象填充是同一个引用
const arr = new Array(3).fill({ x: 0 })
arr[0].x = 1
console.log(arr) // [{ x: 1 }, { x: 1 }, { x: 1 }]
// 正确做法
const arr2 = Array.from({ length: 3 }, () => ({ x: 0 }))
arr2[0].x = 1
console.log(arr2) // [{ x: 1 }, { x: 0 }, { x: 0 }]

copyWithin()#

在数组内部复制元素:

// copyWithin(target, start, end)
// target: 复制到的位置
// start: 复制源的起始位置
// end: 复制源的结束位置(不包含)
;[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5](从位置3开始复制到位置0)
;[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5](只复制一个元素)
;[1, 2, 3, 4, 5].copyWithin(-2, 0, 2)
// [1, 2, 3, 1, 2](负数从末尾计算)

entries()、keys()、values()#

返回遍历器对象:

const arr = ['a', 'b', 'c']
// keys() 返回索引
for (const index of arr.keys()) {
console.log(index) // 0, 1, 2
}
// values() 返回值
for (const value of arr.values()) {
console.log(value) // 'a', 'b', 'c'
}
// entries() 返回 [索引, 值]
for (const [index, value] of arr.entries()) {
console.log(index, value) // 0 'a', 1 'b', 2 'c'
}
// 转为数组
;[...arr.entries()] // [[0, 'a'], [1, 'b'], [2, 'c']]

includes()#

判断数组是否包含某元素:

;[1, 2, 3].includes(2) // true
;[1, 2, 3].includes(4) // false
// 可以检测 NaN
;[1, NaN, 3].includes(NaN) // true
;[1, NaN, 3].indexOf(NaN) // -1(indexOf 无法检测)
// 指定起始位置
;[1, 2, 3].includes(1, 1) // false(从索引1开始查找)
;[1, 2, 3].includes(1, -3) // true(负数从末尾计算)

空位处理#

ES6 明确将数组空位转为 undefined

// ES5 方法对空位处理不一致
;[, , ,].forEach((x) => console.log(x)) // 不输出(跳过空位)
;[, , ,].map((x) => 1) // [empty × 3](跳过空位)
// ES6 方法统一处理为 undefined
Array.from([, , ,]) // [undefined, undefined, undefined]
;[...[, , ,]] // [undefined, undefined, undefined]
;[, , ,].fill(1) // [1, 1, 1]
// for...of 也会遍历空位
for (const x of [, , ,]) {
console.log(x) // undefined, undefined, undefined
}

实战应用#

数组分组#

function groupBy(arr, fn) {
return arr.reduce((groups, item) => {
const key = fn(item)
;(groups[key] = groups[key] || []).push(item)
return groups
}, {})
}
const users = [
{ name: '张三', age: 25 },
{ name: '李四', age: 30 },
{ name: '王五', age: 25 },
]
groupBy(users, (u) => u.age)
// { 25: [{...}, {...}], 30: [{...}] }

数组分块#

function chunk(arr, size) {
return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
)
}
chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]

数组打乱#

function shuffle(arr) {
const result = [...arr]
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1))
;[result[i], result[j]] = [result[j], result[i]]
}
return result
}
shuffle([1, 2, 3, 4, 5]) // [3, 1, 5, 2, 4](随机)

数组去重(保持顺序)#

function unique(arr, key) {
if (key) {
const seen = new Set()
return arr.filter((item) => {
const k = item[key]
if (seen.has(k)) return false
seen.add(k)
return true
})
}
return [...new Set(arr)]
}
unique([1, 2, 2, 3]) // [1, 2, 3]
unique([{ id: 1 }, { id: 2 }, { id: 1 }], 'id') // [{ id: 1 }, { id: 2 }]

方法汇总#

方法作用返回值
Array.from()类数组转数组新数组
Array.of()创建数组新数组
find()查找元素元素或 undefined
findIndex()查找索引索引或 -1
findLast()从后查找元素元素或 undefined
findLastIndex()从后查找索引索引或 -1
fill()填充数组修改后的原数组
copyWithin()内部复制修改后的原数组
includes()是否包含boolean
entries()键值对迭代器Iterator
keys()键迭代器Iterator
values()值迭代器Iterator

这些方法让数组操作更加直观和便捷,熟练掌握可以写出更简洁的代码。