数组遍历方式:
-
for循环
-
for...of
-
forEach
-
map
-
filter
-
reduce
-
some / every
-
find / findIndex
-
for...in(不推荐,但可以说避免使用)
对象遍历方式:
-
for...in
-
Object.keys()
-
Object.values()
-
Object.entries()
-
Object.getOwnPropertyNames()
-
Reflect.ownKeys()
-
for...of + Object.entries()
每个场景都要简短说明为什么选这个方法。
注意代码格式,保持清晰。
由于回答可能较长,我将组织成有标题的形式,但避免markdown过多层级。
以下是常用数组和对象遍历 API 的实际使用场景,每个都给出了典型示例和选择理由。
一、数组遍历
1. for 循环
场景:需要在遍历过程中动态修改数组长度、提前跳出(break),或者对性能要求极高的场合。
javascript
// 场景:删除数组中所有值为 null 的元素(从后往前删除,避免索引错位)
let arr = [1, null, 2, null, 3];
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i] === null) {
arr.splice(i, 1);
}
}
// arr -> [1, 2, 3]
2. for...of
场景:只需要元素值,并可能提前退出(break/continue),代码简洁。
javascript
// 场景:检查数组中是否包含某个值,一旦找到就停止
const ids = [101, 205, 307, 409];
let targetId = 307;
let found = false;
for (const id of ids) {
if (id === targetId) {
found = true;
break;
}
}
3. forEach
场景:单纯执行副作用(如打印、更新外部状态),不需要中断循环。
javascript
// 场景:批量更新页面上的元素内容
const elements = document.querySelectorAll('.item');
elements.forEach((el, index) => {
el.textContent = `第 ${index + 1} 项`;
});
4. map
场景:从原数组生成一个新数组,且新数组长度相同。
javascript
// 场景:将用户对象数组转换为只包含用户名的数组
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const names = users.map(user => user.name);
// names -> ['Alice', 'Bob']
5. filter
场景:根据条件筛选出子集。
javascript
// 场景:获取所有已完成的任务
const tasks = [
{ title: '学习JS', done: true },
{ title: '写报告', done: false }
];
const completed = tasks.filter(task => task.done);
6. reduce
场景:将数组归约为单个值(累加、合并对象、分组等)。
javascript
// 场景:统计商品总价
const cart = [
{ name: '苹果', price: 5, count: 2 },
{ name: '香蕉', price: 3, count: 3 }
];
const total = cart.reduce((sum, item) => sum + item.price * item.count, 0);
// total -> 19
7. some / every
场景:快速判断数组是否满足某些条件。
javascript
// some: 检查数组中是否存在未支付订单
const orders = [
{ id: 1, paid: true },
{ id: 2, paid: false }
];
const hasUnpaid = orders.some(order => !order.paid); // true
// every: 检查所有学生是否都及格
const scores = [85, 92, 78, 88];
const allPass = scores.every(score => score >= 60); // true
8. find / findIndex
场景:查找第一个符合条件的元素或其索引。
javascript
// 场景:根据 id 查找用户对象
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const user = users.find(u => u.id === 2);
// user -> { id: 2, name: 'Bob' }
9. for...in(避免用于数组)
不推荐,因为它会遍历数组对象上所有可枚举属性(包括原型链),且不保证顺序。
如果误用可能造成问题,例如:
javascript
Array.prototype.custom = 'foo';
const arr = [1, 2];
for (let i in arr) {
console.log(i); // 输出 "0", "1", "custom"
}
二、对象遍历
1. for...in
场景:需要遍历对象自身及原型链上的可枚举属性(通常配合 hasOwnProperty 过滤)。
javascript
// 场景:复制对象自身属性(不包括原型)
const source = { a: 1, b: 2 };
const target = {};
for (let key in source) {
if (source.hasOwnProperty(key)) {
target[key] = source[key];
}
}
2. Object.keys()
场景:获取对象自身可枚举属性名,然后结合数组方法处理。
javascript
// 场景:遍历对象并执行操作
const config = { host: 'localhost', port: 8080, ssl: false };
Object.keys(config).forEach(key => {
console.log(`${key}: ${config[key]}`);
});
3. Object.values()
场景:只需要对象的值。
javascript
// 场景:计算所有学生成绩的总分
const scores = { math: 95, english: 88, science: 92 };
const total = Object.values(scores).reduce((sum, score) => sum + score, 0);
// total -> 275
4. Object.entries()
场景:同时需要键和值,是最常用的对象遍历方式。
javascript
// 场景:将对象转换为查询字符串
const params = { search: 'js', page: 1, limit: 10 };
const queryString = Object.entries(params)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&');
// queryString -> "search=js&page=1&limit=10"
5. Object.getOwnPropertyNames()
场景:需要遍历对象的不可枚举属性(如某些内置属性)。
javascript
// 场景:获取对象所有自身属性(包括不可枚举的)
const obj = {};
Object.defineProperty(obj, 'hidden', { value: 42, enumerable: false });
console.log(Object.getOwnPropertyNames(obj)); // ['hidden']
6. Reflect.ownKeys()
场景:需要完整获取对象所有自身属性键,包括 Symbol 类型。
javascript
// 场景:深拷贝对象时保留 Symbol 属性
const sym = Symbol('id');
const obj = { name: 'foo', [sym]: 123 };
const clone = {};
Reflect.ownKeys(obj).forEach(key => {
clone[key] = obj[key];
});
console.log(clone); // { name: 'foo', [sym]: 123 }
7. for...of + Object.entries()
场景:需要遍历对象的同时可以随时中断(break)。
javascript
// 场景:查找对象中第一个值大于 100 的键值对
const data = { a: 50, b: 120, c: 80 };
let foundKey = null;
for (const [key, value] of Object.entries(data)) {
if (value > 100) {
foundKey = key;
break;
}
}
// foundKey -> 'b'
选择总结
| 场景需求 | 推荐 API |
|---|---|
| 数组需中断、高性能 | for 或 for...of |
| 数组执行副作用,不中断 | forEach |
| 数组转换(映射、筛选、归约) | map、filter、reduce |
| 数组条件判断 | some、every、find |
| 对象遍历自身可枚举属性 | Object.entries() + forEach / for...of |
| 对象只需键或值 | Object.keys()、Object.values() |
| 对象需包含不可枚举或 Symbol 属性 | Object.getOwnPropertyNames()、Reflect.ownKeys() |
| 对象需要中途跳出 | for...of + Object.entries() |

1249

被折叠的 条评论
为什么被折叠?



