一、创建数组的几种方式
在 JavaScript 中,创建数组有多种方式,每种方式都有自己的适用场景:
// 1. 字面量方式(推荐,简洁直观)
const fruits = ['苹果', '香蕉', '橙子']
// 2. 构造函数方式
const numbers = new Array(1, 2, 3)
// 3. Array.of(解决 new Array 的怪异行为)
const single = Array.of(5) // [5]
const weird = new Array(5) // [empty × 5]
// 4. Array.from(从类数组或可迭代对象创建)
const chars = Array.from('小明') // ['小', '明']
建议:日常开发中,优先使用字面量方式,简洁且不易出错。Array.of
和 Array.from
适合特殊场景,比如处理类数组或明确需要单个元素数组时。
二、遍历数组的正确姿势
遍历数组是开发中最常见的需求之一,JavaScript 提供了多种方法,适合不同场景。我们来逐一分析。
1. 基础遍历方法
for 循环
传统且灵活,可以精确控制遍历过程:
const fruits = ['苹果', '香蕉', '橙子']
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i])
}
优点:支持 break
和 continue
,适合需要中断或跳过循环的场景。
缺点:代码稍显冗长。
for...of 循环
ES6 引入,语法简洁,专注于元素本身:
for (const fruit of fruits) {
console.log(fruit)
}
优点:简洁直观,适合简单遍历。
缺点:无法直接访问索引(可以通过 entries()
获取)。
forEach 方法
数组内置方法,适合快速遍历:
fruits.forEach((fruit, index) => {
console.log(`第 ${index} 个水果是: ${fruit}`)
})
优点:函数式风格,代码简洁。
缺点:无法使用 break
或 return
中断。
2. 功能性遍历方法
map 方法
将数组转换为新数组,常用于数据转换:
const numbers = [1, 2, 3, 4]
const doubled = numbers.map(num => num * 2)
// 结果: [2, 4, 6, 8]
场景:需要生成新数组,比如计算折扣价格、格式化数据。
filter 方法
筛选符合条件的元素:
const scores = [75, 90, 45, 60, 88]
const passingScores = scores.filter(score => score >= 60)
// 结果: [75, 90, 60, 88]
场景:过滤数据,比如显示通过考试的学生、筛选价格低于某值的商品。
reduce 方法
将数组归约为单个值,功能强大:
const numbers = [1, 2, 3, 4, 5]
const sum = numbers.reduce((total, current) => total + current, 0)
// 结果: 15
场景:求和、统计、复杂数据聚合。
3. 查找类方法
find 和 findIndex
快速找到符合条件的元素或其索引:
const users = [
{ name: '张三', age: 28 },
{ name: '李四', age: 17 },
{ name: '王五', age: 32 }
]
const adult = users.find(user => user.age >= 18) // { name: '张三', age: 28 }
const adultIndex = users.findIndex(user => user.age >= 18) // 0
场景:查找特定用户、商品等。
some 和 every
检查数组是否满足某些条件:
const ages = [18, 21, 28, 16]
const hasMinor = ages.some(age => age < 18) // true
const allAdults = ages.every(age => age >= 18) // false
场景:验证数据,比如检查是否所有人成年、是否至少有一个低价商品。
4. 其他遍历方法
for...in 循环
主要为对象设计,不推荐用于数组:
for (const index in fruits) {
console.log(fruits[index])
}
问题:可能遍历到继承的属性,性能较差。
while 和 do-while
适合不确定循环次数的场景:
let i = 0
while (i < fruits.length) {
console.log(fruits[i])
i++
}
场景:动态条件控制,比如处理用户输入。
5. 选择建议
- 简单遍历:用
for...of
或 forEach
,代码简洁。
- 需要中断:用
for
循环,支持 break
。
- 数据转换:用
map
、filter
、reduce
。
- 性能敏感:
for
循环通常最快,但差距不大,除非处理超大数组。
三、添加和删除元素
数组的增删操作很常见,以下是常用方法:
const team = ['张三', '李四']
// 末尾操作
team.push('王五') // 添加,返回新长度 3
const last = team.pop() // 删除,返回 '王五'
// 开头操作
team.unshift('赵六') // 添加,返回新长度 3
const first = team.shift() // 删除,返回 '赵六'
// 任意位置操作
team.splice(1, 0, '钱七') // 插入 '钱七'
team.splice(0, 1) // 删除索引 0 的元素
注意:splice
会修改原数组,谨慎使用。
四、数组转换与处理
1. 连接与分割
const colors = ['红', '绿', '蓝']
const colorString = colors.join('和') // '红和绿和蓝'
const primaryColors = colors.slice(0, 2) // ['红', '绿']
const moreColors = colors.concat(['黄', '紫']) // ['红', '绿', '蓝', '黄', '紫']
2. 扁平化数组
处理嵌套数组时,flat
是最简单的方法:
const nested = [1, [2, [3, 4]]]
const flattened = nested.flat(Infinity) // [1, 2, 3, 4]
手动实现扁平化(递归方式):
function flatten(arr) {
return arr.reduce((acc, val) => {
return acc.concat(Array.isArray(val) ? flatten(val) : val)
}, [])
}
性能提示:内置 flat()
通常最快,递归方法适合自定义需求。
3. 排序与查找
const fruits = ['香蕉', '苹果', '橙子']
fruits.sort() // ['橙子', '苹果', '香蕉']
fruits.reverse() // ['香蕉', '葡萄', '苹果']
const scores = [40, 100, 1, 5]
scores.sort((a, b) => a - b) // [1, 5, 40, 100]
const appleIndex = fruits.indexOf('苹果') // 2
const hasOrange = fruits.includes('橙子') // true
现代方法(ES2022+):
const numbers = [3, 1, 4, 2]
const sorted = numbers.toSorted() // [1, 2, 3, 4],不改原数组
const reversed = numbers.toReversed() // [2, 4, 1, 3]
const modified = numbers.with(0, 9) // [9, 1, 4, 2]
五、去重操作
数组去重是常见需求,Set
是最简洁高效的方法:
const arr = [1, 2, 2, 3, 3]
const unique = [...new Set(arr)] // [1, 2, 3]
对于对象数组,按特定键去重:
const objArr = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 1, name: '张三' }
]
const uniqueObjArr = Array.from(
new Map(objArr.map(item => [item.id, item])).values()
)
// 结果: [{ id: 1, name: '张三' }, { id: 2, name: '李四' }]
性能提示:Set
方法对简单类型最快,Map
适合对象数组。
六、类数组的处理
类数组(如 arguments
、NodeList)有 length
和索引,但无数组方法。转换方法:
function example() {
const args = Array.from(arguments) // 或 [...arguments]
return args.map(x => x * 2)
}
console.log(example(1, 2, 3)) // [2, 4, 6]
场景:处理 DOM 元素集合、函数参数等。
七、总结
数组操作是 JavaScript 开发的基石。从基础的 for
循环到现代的 toSorted
、flat
,每种方法都有其独特价值。记住以下几点:
- 简单优先:用
for...of
或 forEach
处理简单遍历。
- 函数式编程:
map
、filter
、reduce
让代码更优雅。
- 性能优化:大数组用
Set
去重,for
循环遍历。
- 现代特性:ES2022+ 的方法(如
toSorted
)更安全,优先考虑。