数组遍历
# 数组遍历
在前端开发中,数组操作非常频繁,选择合适的循环遍历方法不仅能提升开发效率,还能优化代码的可读性和维护性。本文将详细介绍前端常用的数组遍历方法,包括 for
循环、forEach
、map
、filter
、reduce
等,帮助开发者更好地掌握这些技巧。
# 1. for
循环 vs forEach
方法对比
- for 循环:经典、通用,操作索引直接,性能最佳。适合需要频繁操作或提前退出循环的场景。支持
break
跳出循环,适用于需要条件中止循环的场景。 - forEach:高阶函数,简洁优雅,提升代码可读性,但带来额外的函数调用开销。不能中断循环,不支持
break
语句,仅能跳过某次迭代(使用return
)。
# 1.1 性能比较
let arrs = [...Array(9999999).keys()]; // 生成一个包含 0 到 9999998 的大数组
let total = 0;
let startTime = Date.now(); // 记录开始时间
// 使用 for 循环遍历数组
for(let i = 0; i < arrs.length; i++) {
total += arrs[i]; // 将数组中的每个元素累加
}
let endTime = Date.now(); // 记录结束时间
console.log("计数: " + total); // 计算数组元素总和
console.log("for 循环消耗时间: " + (endTime - startTime) + "ms"); // 计算执行时间
2
3
4
5
6
7
8
9
10
11
输出结果:
for
循环性能高,特别是在处理大数据时显得尤为重要。
# 1.2 break
与 forEach
的差异
for
循环支持 break
跳出循环,而 forEach
不支持。可以使用 return
跳过当前的迭代。
- 使用
for
循环的break
:当满足条件时跳出循环,避免多余计算。
let arrs = [...Array(9999999).keys()];
let total = 0;
let startTime = Date.now();
// 在满足某个条件时跳出循环
for(let i = 0; i < arrs.length; i++){
if(i === 10) break; // 遇到 i 为 10 时退出循环
total += arrs[i]; // 累加数组中前10个元素的值
}
let endTime = Date.now();
console.log("计数: " + total); // 输出: 45
console.log("for 循环消耗时间: " + (endTime - startTime) + "ms"); // 时间大幅减少
2
3
4
5
6
7
8
9
10
11
12
13
- 使用
forEach
时无法直接break
:
let arrs = [...Array(9999999).keys()];
let total = 0;
let startTime = Date.now();
// forEach 无法中断,只能通过 return 跳过当前迭代
arrs.forEach(item => {
if(item > 10) return; // 当元素大于 10 时跳过剩下的计算
total += item;
});
let endTime = Date.now();
console.log("计数: " + total); // 输出: 55
console.log("forEach 消耗时间: " + (endTime - startTime) + "ms");
2
3
4
5
6
7
8
9
10
11
12
13
总结:for
循环在处理大量数据、需要中止时更高效,而 forEach
更适合追求简洁的代码场景。
# 2. map()
方法 —— 高效生成新数组
map()
是一种常用方法,它会遍历数组,并返回一个新数组。原数组不被修改,非常适合需要对数组每个元素进行处理,并返回新的数组的场景。
# 2.1 将数组内每个元素乘以 2
let arrs = [1, 2, 3, 4];
let newArrs = arrs.map(item => item * 2); // 对每个元素乘以 2,生成新数组
console.log(newArrs); // 输出: [2, 4, 6, 8]
2
3
map()
遍历原数组的每个元素,并将返回值存储到新数组中。
# 2.2 修改对象属性并生成新数组
let products = [
{ name: "华为", price: 6999 },
{ name: "苹果", price: 9888 }
];
// 修改对象的 price 格式,并为每个对象增加一个新属性 inStock
let updatedProducts = products.map(item => ({
...item, // 解构原有对象
price: item.price + "元", // 将价格改为字符串格式
inStock: true // 增加新属性表示有库存
}));
console.log(updatedProducts); // 输出修改后的新数组
2
3
4
5
6
7
8
9
10
11
12
map()
非常适合用于对数组中的对象进行深度处理,同时返回新对象数组。
# 3. filter()
方法 —— 过滤数组中的元素
filter()
方法用于筛选出符合条件的数组元素,生成一个新数组。原数组不受影响,适合需要根据条件过滤数据的场景。
# 3.1 过滤数组中大于 10 的数值
let numbers = [5, 7, 12, 15, 22, 2];
let filteredNumbers = numbers.filter(num => num > 10); // 过滤出大于 10 的元素
console.log(filteredNumbers); // 输出: [12, 15, 22]
2
3
filter()
遍历数组,返回满足条件(回调函数返回true
)的元素。
# 3.2 从对象数组中过滤掉无用数据
let items = [
{ id: 1, name: "A" },
{ id: null, name: "B" },
{ id: 3, name: "C" }
];
// 过滤掉 id 为 null 的对象
let validItems = items.filter(item => item.id !== null);
console.log(validItems); // 输出: [{ id: 1, name: "A" }, { id: 3, name: "C" }]
2
3
4
5
6
7
8
9
- 通过过滤条件
item.id !== null
,我们可以从数组中去掉无效的数据。
# 4. reduce()
方法 —— 数组求和与聚合
reduce()
是数组的一个强大方法,允许我们对数组中的所有元素进行逐步累加或聚合处理,最终返回一个累积值。可以用它来实现很多操作,比如数组求和、求积、累加对象属性的值、统计次数等等。
基本概念
reduce()
方法会对数组中的每个元素执行 回调函数,并将其结果累积到一个单一的值。这个累积的值就是我们最终想要的结果。该方法接收两个参数:
- 回调函数:每次执行的操作,它处理每个元素并返回累加结果。
- 初始值(可选):累加器的初始值,默认是数组的第一个元素(如果没有传递的话)。
reduce()
方法的语法
array.reduce(callback(accumulator, currentValue, index, array), initialValue);
参数说明
callback
:对每个元素执行的函数,包含以下参数:accumulator
:上一次调用回调函数的返回值,或者是提供的初始值initialValue
(如果存在)。currentValue
:当前正在处理的数组元素。index
(可选):当前元素的索引。array
(可选):调用reduce()
的数组。
initialValue
(可选):作为第一次调用callback
函数时的accumulator
值。如果没有提供initialValue
,数组的第一个元素会作为accumulator
,从第二个元素开始处理数组。
# 4.1 数组求和示例
假设我们有一个数组 [1, 2, 3, 4]
,想要计算数组元素的总和,可以通过 reduce()
轻松实现。
let arrs = [1, 2, 3, 4];
// 使用 reduce 将数组中的所有元素累加
let total = arrs.reduce((accumulator, currentValue) => {
// accumulator: 当前累加的结果
// currentValue: 当前遍历的数组元素
return accumulator + currentValue;
}, 0); // 初始值设为 0
console.log(total); // 输出: 10
2
3
4
5
6
7
8
9
10
执行过程分析:
- 第一轮:
accumulator = 0
(初始值),currentValue = 1
,结果是0 + 1 = 1
。 - 第二轮:
accumulator = 1
(上一次的结果),currentValue = 2
,结果是1 + 2 = 3
。 - 第三轮:
accumulator = 3
(上一次的结果),currentValue = 3
,结果是3 + 3 = 6
。 - 第四轮:
accumulator = 6
(上一次的结果),currentValue = 4
,结果是6 + 4 = 10
。
最终返回 10
,即数组 [1, 2, 3, 4]
的总和。
# 4.2 对数组对象中的某个字段进行累加
有时我们处理的不是简单的数字数组,而是对象数组。比如我们有一个对象数组,每个对象代表一个人的信息,想要统计这些人的总年龄,可以用 reduce()
来累加每个对象的 age
属性。
示例:
let people = [
{ name: "张三", age: 29 },
{ name: "李四", age: 16 },
{ name: "王五", age: 50 }
];
// 使用 reduce 累加所有人的年龄
let totalAge = people.reduce((accumulator, currentPerson) => {
// accumulator: 累加到目前的年龄总和
// currentPerson: 当前正在处理的对象
return accumulator + currentPerson.age; // 只累加对象的 age 属性
}, 0); // 初始值设为 0
console.log(totalAge); // 输出: 95
2
3
4
5
6
7
8
9
10
11
12
13
14
执行过程分析:
- 第一轮:
accumulator = 0
(初始值),currentPerson = { name: "张三", age: 29 }
,结果是0 + 29 = 29
。 - 第二轮:
accumulator = 29
(上一次的结果),currentPerson = { name: "李四", age: 16 }
,结果是29 + 16 = 45
。 - 第三轮:
accumulator = 45
(上一次的结果),currentPerson = { name: "王五", age: 50 }
,结果是45 + 50 = 95
。
最终返回 95
,即所有人的总年龄。
# 5. every()
方法 —— 全部满足条件时返回 true
every()
方法用于检查数组中的所有元素是否都满足指定条件。只要有一个元素不符合条件,every()
就会返回false
。
# 5.1 检查数组是否全部为正数
let numbers = [1, 2, 3, 4];
let allPositive = numbers.every(num => num > 0); // 检查所有元素是否大于 0
console.log(allPositive); // 输出: true
2
3
- 如果数组中的所有元素都满足条件,
every()
返回true
。
# 5.2 检查数组对象中的商品是否都有库存
let products = [
{ name: "华为", stock: true },
{ name: "苹果", stock: false },
{ name: "小米", stock: true }
];
// 检查所有商品是否都有库存
let allInStock = products.every(item => item.stock);
console.log(allInStock); // 输出: false
2
3
4
5
6
7
8
9
- 如果数组中有一个元素不满足条件,
every()
返回false
。
# 6. some()
方法 —— 至少一个元素满足条件时返回 true
some()
与every()
相反,它只要求数组中至少有一个元素满足条件时就返回true
。
# 6.1 检查数组中是否有小于 10 的元素
let numbers = [15, 8, 12, 20];
let hasSmallNumbers = numbers.some(num => num < 10); // 检查是否存在小于 10 的数
console.log(hasSmallNumbers); // 输出: true
2
3
- 只要有一个元素满足条件,
some()
就会返回true
。
# 6.2 检查对象数组中是否有商品库存量不足
let products = [
{ name: "华为", stock: true },
{ name: "苹果", stock: false },
{ name: "小米", stock: true }
];
// 检查是否有商品无库存
let anyOutOfStock = products.some(item => !item.stock);
console.log(anyOutOfStock); // 输出: true
2
3
4
5
6
7
8
9
some()
可用于快速查找数组中是否存在符合条件的元素。
# 7. includes()
方法 —— 检查数组是否包含特定值
includes()
用于检查数组中是否包含某个特定的元素。只适用于基础数据类型(如数字、字符串)。
# 7.1 检查数组是否包含某个数值
let arr = [1, 2, 3, 4];
console.log(arr.includes(3)); // 输出: true
console.log(arr.includes(5)); // 输出: false
2
3
includes()
可用于快速查找数组中是否包含指定值。
总结
以上数组遍历方法各有优势,应根据具体场景合理选择:
for
循环适合简单、需要跳出循环的场景,性能较高。forEach
提升代码可读性,适合简洁场景,但不支持中途退出。map
、filter
、reduce
适用于复杂数据处理和生成新数组的场景,尤其是在对数据进行转换、筛选和汇总时。