数组和对象常用遍历方式
数组遍历方式:
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 -> 197.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); // true8.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 -> 2754.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() |
