Skip to content

数组基础

数组是有序的数据集合,是 JavaScript 中最常用的数据结构之一。

🎯 创建数组#

数组字面量#

// 最常用的方式
const fruits = ['苹果', '香蕉', '橘子']
// 空数组
const empty = []
// 混合类���(不推荐)
const mixed = [1, 'hello', true, { name: '张三' }, [1, 2]]
// 稀疏数组(有空位)
const sparse = [1, , , 4]
console.log(sparse.length) // 4
console.log(sparse[1]) // undefined

Array 构造函数#

// 单个数字参数:创建指定长度的空数组
const arr1 = new Array(3)
console.log(arr1.length) // 3
console.log(arr1[0]) // undefined
// 多个参数:创建包含这些元素的数组
const arr2 = new Array(1, 2, 3)
console.log(arr2) // [1, 2, 3]
// 🔶 单参数时容易混淆,建议用 Array.of
const arr3 = Array.of(3)
console.log(arr3) // [3]

Array.from#

// 从类数组创建
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
const arr1 = Array.from(arrayLike)
console.log(arr1) // ["a", "b", "c"]
// 从字符串创建
const arr2 = Array.from('hello')
console.log(arr2) // ["h", "e", "l", "l", "o"]
// 从 Set 创建
const set = new Set([1, 2, 2, 3])
const arr3 = Array.from(set)
console.log(arr3) // [1, 2, 3]
// 带映射函数
const arr4 = Array.from([1, 2, 3], (x) => x * 2)
console.log(arr4) // [2, 4, 6]
// 生成序列
const sequence = Array.from({ length: 5 }, (_, i) => i + 1)
console.log(sequence) // [1, 2, 3, 4, 5]

Array.fill 填充#

// 创建并填充
const zeros = new Array(5).fill(0)
console.log(zeros) // [0, 0, 0, 0, 0]
// 填充指定范围
const arr = [1, 2, 3, 4, 5]
arr.fill(0, 1, 3) // 从索引1到3(不含)
console.log(arr) // [1, 0, 0, 4, 5]
// 🔶 fill 对引用类型是共享的
const refs = new Array(3).fill([])
refs[0].push(1)
console.log(refs) // [[1], [1], [1]](三个是同一个数组!)
// 正确创建独立数组
const independent = Array.from({ length: 3 }, () => [])
independent[0].push(1)
console.log(independent) // [[1], [], []]

索引访问#

读取和修改#

const arr = ['a', 'b', 'c', 'd', 'e']
// 读取
console.log(arr[0]) // "a"
console.log(arr[2]) // "c"
console.log(arr[-1]) // undefined(不支持负索引)
// 使用 at() 支持负索引(ES2022)
console.log(arr.at(0)) // "a"
console.log(arr.at(-1)) // "e"(最后一个)
console.log(arr.at(-2)) // "d"
// 修改
arr[1] = 'B'
console.log(arr) // ["a", "B", "c", "d", "e"]
// 超出范围添加(会产生空位)
arr[10] = 'x'
console.log(arr.length) // 11
console.log(arr[7]) // undefined

length 属性#

const arr = [1, 2, 3, 4, 5]
// 获取长度
console.log(arr.length) // 5
// 设置 length 可以截断或扩展数组
arr.length = 3
console.log(arr) // [1, 2, 3]
arr.length = 5
console.log(arr) // [1, 2, 3, empty × 2]
// 清空数组
arr.length = 0
console.log(arr) // []

添加和删除元素#

push 和 pop(尾部操作)#

const arr = [1, 2, 3]
// push:添加到末尾,返回新长度
const len = arr.push(4, 5)
console.log(arr) // [1, 2, 3, 4, 5]
console.log(len) // 5
// pop:移除最后一个,返回移除的元素
const last = arr.pop()
console.log(arr) // [1, 2, 3, 4]
console.log(last) // 5
// 空数组 pop 返回 undefined
console.log([].pop()) // undefined

unshift 和 shift(头部操作)#

const arr = [1, 2, 3]
// unshift:添加到开头,返回新长度
arr.unshift(0)
console.log(arr) // [0, 1, 2, 3]
// shift:移除第一个,返回移除的元素
const first = arr.shift()
console.log(arr) // [1, 2, 3]
console.log(first) // 0
// 🔶 头部操作比尾部操作慢(需要移动其他元素)

splice(任意位置操作)#

const arr = [1, 2, 3, 4, 5]
// splice(start, deleteCount, ...items)
// 删除元素
const removed = arr.splice(2, 2) // 从索引2删除2个
console.log(arr) // [1, 2, 5]
console.log(removed) // [3, 4]
// 插入元素
arr.splice(2, 0, 'a', 'b') // 在索引2插入,不删除
console.log(arr) // [1, 2, "a", "b", 5]
// 替换元素
arr.splice(2, 2, 3, 4) // 删除2个,插入2个
console.log(arr) // [1, 2, 3, 4, 5]
// 负索引
arr.splice(-1, 1) // 删除最后一个
console.log(arr) // [1, 2, 3, 4]

concat(合并数组)#

const arr1 = [1, 2]
const arr2 = [3, 4]
const arr3 = [5, 6]
// 不修改原数组,返回新数组
const combined = arr1.concat(arr2, arr3)
console.log(combined) // [1, 2, 3, 4, 5, 6]
console.log(arr1) // [1, 2](原数组不变)
// 也可以传入单个值
const extended = arr1.concat(3, 4, [5, 6])
console.log(extended) // [1, 2, 3, 4, 5, 6]
// 使用展开运算符(更常用)
const merged = [...arr1, ...arr2, ...arr3]

查找元素#

indexOf 和 lastIndexOf#

const arr = [1, 2, 3, 2, 1]
// indexOf:从前往后找
console.log(arr.indexOf(2)) // 1
console.log(arr.indexOf(5)) // -1(未找到)
// 指定起始位置
console.log(arr.indexOf(2, 2)) // 3
// lastIndexOf:从后往前找
console.log(arr.lastIndexOf(2)) // 3
// 🔶 使用严格相等比较
console.log([1, 2, 3].indexOf('2')) // -1
console.log([NaN].indexOf(NaN)) // -1(NaN 不等于自身)

includes#

const arr = [1, 2, 3, NaN]
console.log(arr.includes(2)) // true
console.log(arr.includes(5)) // false
// 可以找到 NaN
console.log(arr.includes(NaN)) // true(indexOf 做不到)
// 指定起始位置
console.log(arr.includes(1, 1)) // false

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
const notFound = users.find((u) => u.id === 5)
console.log(notFound) // undefined
// findIndex:返回第一个满足条件的索引
const index = users.findIndex((u) => u.name === '王五')
console.log(index) // 2
// findLast 和 findLastIndex(ES2023)
const lastEven = [1, 2, 3, 4, 5].findLast((n) => n % 2 === 0)
console.log(lastEven) // 4

遍历方法#

forEach#

const arr = ['a', 'b', 'c']
arr.forEach((item, index, array) => {
console.log(index, item)
})
// 0 "a"
// 1 "b"
// 2 "c"
// 🔶 forEach 不能中断
arr.forEach((item) => {
if (item === 'b') return // 只是跳过当前迭代
console.log(item)
})
// 输出 a 和 c
// 需要中断时使用 for...of 或 some/every

map(映射)#

const numbers = [1, 2, 3, 4, 5]
// 返回新数组
const doubled = numbers.map((n) => n * 2)
console.log(doubled) // [2, 4, 6, 8, 10]
console.log(numbers) // [1, 2, 3, 4, 5](原数组不变)
// 提取对象属性
const users = [
{ name: '张三', age: 25 },
{ name: '李四', age: 30 },
]
const names = users.map((u) => u.name)
console.log(names) // ["张三", "李四"]
// 链式调用
const result = numbers.map((n) => n * 2).map((n) => n + 1)
console.log(result) // [3, 5, 7, 9, 11]

filter(过滤)#

const numbers = [1, 2, 3, 4, 5, 6]
// 返回满足条件的元素
const evens = numbers.filter((n) => n % 2 === 0)
console.log(evens) // [2, 4, 6]
// 过滤对象数组
const users = [
{ name: '张三', age: 25, active: true },
{ name: '李四', age: 30, active: false },
{ name: '王五', age: 28, active: true },
]
const activeUsers = users.filter((u) => u.active)
console.log(activeUsers.length) // 2
// 移除假值
const mixed = [0, 1, '', 'hello', null, undefined, false, true]
const truthy = mixed.filter(Boolean)
console.log(truthy) // [1, "hello", true]

reduce(归约)#

const numbers = [1, 2, 3, 4, 5]
// 求和
const sum = numbers.reduce((acc, cur) => acc + cur, 0)
console.log(sum) // 15
// 求最大值
const max = numbers.reduce((a, b) => (a > b ? a : b))
console.log(max) // 5
// 数组转对象
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
]
const userMap = users.reduce((map, user) => {
map[user.id] = user
return map
}, {})
console.log(userMap) // { 1: {...}, 2: {...} }
// 扁平化数组
const nested = [[1, 2], [3, 4], [5]]
const flat = nested.reduce((acc, cur) => acc.concat(cur), [])
console.log(flat) // [1, 2, 3, 4, 5]
// 分组
const items = [
{ type: 'fruit', name: '苹果' },
{ type: 'vegetable', name: '白菜' },
{ type: 'fruit', name: '香蕉' },
]
const grouped = items.reduce((groups, item) => {
const key = item.type
groups[key] = groups[key] || []
groups[key].push(item)
return groups
}, {})
// { fruit: [...], vegetable: [...] }
// Object.groupBy(ES2024)
const grouped2 = Object.groupBy(items, (item) => item.type)

some 和 every#

const numbers = [1, 2, 3, 4, 5]
// some:至少有一个满足条件
console.log(numbers.some((n) => n > 3)) // true
console.log(numbers.some((n) => n > 10)) // false
// every:所有都满足条件
console.log(numbers.every((n) => n > 0)) // true
console.log(numbers.every((n) => n > 3)) // false
// 可以提前终止
const arr = [1, 2, 3, 4, 5]
arr.some((n) => {
console.log(n)
return n === 3 // 找到 3 后停止
})
// 输出 1, 2, 3

排序#

sort#

// 默认按字符串排序
const arr = [10, 2, 1, 21]
arr.sort()
console.log(arr) // [1, 10, 2, 21](字符串顺序)
// 数字排序需要比较函数
arr.sort((a, b) => a - b) // 升序
console.log(arr) // [1, 2, 10, 21]
arr.sort((a, b) => b - a) // 降序
console.log(arr) // [21, 10, 2, 1]
// 对象排序
const users = [
{ name: '张三', age: 30 },
{ name: '李四', age: 25 },
{ name: '王五', age: 28 },
]
users.sort((a, b) => a.age - b.age)
// 按年龄升序
// 字符串排序
const names = ['张三', '李四', '王五']
names.sort((a, b) => a.localeCompare(b, 'zh-CN'))
// 🔶 sort 会修改原数组

toSorted(ES2023,不可变)#

const arr = [3, 1, 2]
const sorted = arr.toSorted((a, b) => a - b)
console.log(sorted) // [1, 2, 3]
console.log(arr) // [3, 1, 2](原数组不变)

reverse#

const arr = [1, 2, 3, 4, 5]
arr.reverse()
console.log(arr) // [5, 4, 3, 2, 1]
// toReversed(ES2023,不可变)
const arr2 = [1, 2, 3]
const reversed = arr2.toReversed()
console.log(reversed) // [3, 2, 1]
console.log(arr2) // [1, 2, 3](原数组不变)

数组转换#

slice(切片)#

const arr = [1, 2, 3, 4, 5]
// 提取子数组(不修改原数组)
console.log(arr.slice(1, 4)) // [2, 3, 4]
console.log(arr.slice(2)) // [3, 4, 5]
console.log(arr.slice(-2)) // [4, 5]
console.log(arr.slice(1, -1)) // [2, 3, 4]
// 浅拷贝数组
const copy = arr.slice()

flat(扁平化)#

const nested = [1, [2, [3, [4]]]]
console.log(nested.flat()) // [1, 2, [3, [4]]](默认深度1)
console.log(nested.flat(2)) // [1, 2, 3, [4]]
console.log(nested.flat(Infinity)) // [1, 2, 3, 4](完全扁平)
// flatMap = map + flat(1)
const arr = [1, 2, 3]
const result = arr.flatMap((x) => [x, x * 2])
console.log(result) // [1, 2, 2, 4, 3, 6]

join(转字符串)#

const arr = ['苹果', '香蕉', '橘子']
console.log(arr.join()) // "苹果,香蕉,橘子"
console.log(arr.join('-')) // "苹果-香蕉-橘子"
console.log(arr.join('')) // "苹果香蕉橘子"
// 与 split 配合
const str = 'a-b-c'
const parts = str.split('-')
const rejoined = parts.join('_')
console.log(rejoined) // "a_b_c"

判断数组#

// Array.isArray(推荐)
console.log(Array.isArray([])) // true
console.log(Array.isArray({})) // false
console.log(Array.isArray('hello')) // false
// instanceof(跨 iframe 可能失效)
console.log([] instanceof Array) // true
// Object.prototype.toString
console.log(Object.prototype.toString.call([])) // "[object Array]"

不可变数组方法(ES2023)#

const arr = [3, 1, 2]
// toSorted - 排序
arr.toSorted((a, b) => a - b) // [1, 2, 3]
// toReversed - 反转
arr.toReversed() // [2, 1, 3]
// toSpliced - 替换
arr.toSpliced(1, 1, 'a', 'b') // [3, "a", "b", 2]
// with - 替换单个元素
arr.with(1, 100) // [3, 100, 2]
// 原数组始终不变
console.log(arr) // [3, 1, 2]

实用技巧#

// 去重
const unique = [...new Set([1, 2, 2, 3, 3, 3])]
console.log(unique) // [1, 2, 3]
// 交集
const intersection = [1, 2, 3].filter((x) => [2, 3, 4].includes(x))
console.log(intersection) // [2, 3]
// 差集
const difference = [1, 2, 3].filter((x) => ![2, 3, 4].includes(x))
console.log(difference) // [1]
// 打乱数组
function shuffle(arr) {
return arr.sort(() => Math.random() - 0.5)
}
// 随机取一个
function randomItem(arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
// 分块
function chunk(arr, size) {
return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, (i + 1) * size)
)
}
chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]

总结#

方法作用修改原数组返回值
push/pop尾部操作长度/元素
unshift/shift头部操作长度/元素
splice任意位置操作删除的元素
map映射新数组
filter过滤新数组
reduce归约任意值
find查找元素元素/undefined
sort排序原数组
toSorted排序新数组

核心建议