JavaScript篇:for...in vs for...of:遍历JavaScript数据的正确姿势,你踩坑了吗?

298 阅读4分钟

        大家好,我是江城开朗的豌豆,一名拥有6年以上前端开发经验的工程师。我精通HTML、CSS、JavaScript等基础前端技术,并深入掌握Vue、React、Uniapp、Flutter等主流框架,能够高效解决各类前端开发问题。在我的技术栈中,除了常见的前端开发技术,我还擅长3D开发,熟练使用Three.js进行3D图形绘制,并在虚拟现实与数字孪生技术上积累了丰富的经验,特别是在虚幻引擎开发方面,有着深入的理解和实践。

        我一直认为技术的不断探索和实践是进步的源泉,近年来,我深入研究大数据算法的应用与发展,尤其在数据可视化和交互体验方面,取得了显著的成果。我也注重与团队的合作,能够有效地推动项目的进展和优化开发流程。现在,我担任全栈工程师,拥有CSDN博客专家认证及阿里云专家博主称号,希望通过分享我的技术心得与经验,帮助更多人提升自己的技术水平,成为更优秀的开发者。

大家好,我是前端开发工程师小杨。今天咱们来聊聊 JavaScript 里两个看似相似但完全不同的循环语句——for...in 和 for...of

你是不是也曾经纠结过:

  • for...in 和 for...of 到底该用哪个?
  • 为什么有时候遍历数组会得到奇怪的结果?
  • 遍历对象时,哪种方式更安全?

别急,看完这篇你就全懂了!


1. 一句话总结区别

  • for...in → 遍历对象的可枚举属性(包括原型链)
  • for...of → 遍历可迭代对象的值(Array、Map、Set等)

简单来说:

  • for...in 适合对象(但要注意原型链问题)
  • for...of 适合数组、字符串等可迭代结构

2. for...in:遍历对象的“家底”

for...in 会遍历对象的所有可枚举属性,包括继承自原型链的属性

🌰 举个栗子:遍历对象

const user = { name: '我', age: 25, role: 'developer' };

for (const key in user) {
  console.log(key, user[key]); 
}
// 输出:
// name 我
// age 25
// role developer

看起来没问题?但如果原型链上有属性呢?

Object.prototype.customProp = '来自原型链';

for (const key in user) {
  console.log(key); 
}
// 输出:
// name
// age
// role
// customProp (意外多了一个属性!)

解决方案:用 hasOwnProperty 过滤

for (const key in user) {
  if (user.hasOwnProperty(key)) { // 只遍历自己的属性
    console.log(key);
  }
}
// 输出:
// name
// age
// role

⚠️ 注意:for...in 不保证顺序!

  • 对象的属性遍历顺序不固定(尤其是数字键时)
  • 如果需要顺序,改用 Object.keys() + for...of

3. for...of:专治可迭代对象

for...of 专门用于遍历可迭代对象(Iterable) ,比如:
✅ Array
✅ String
✅ Map / Set
✅ NodeList(DOM 元素集合)
✅ arguments 对象

🌰 举个栗子:遍历数组

const skills = ['JS', 'CSS', 'React'];

for (const skill of skills) {
  console.log(skill);
}
// 输出:
// JS
// CSS
// React

比 for...in 更安全,不会遍历到奇怪的东西!

🌰 再举个栗子:遍历字符串

const name = '我';

for (const char of name) {
  console.log(char);
}
// 输出:
// 我

🚫 for...of 不能直接遍历普通对象!

const user = { name: '我' };

for (const val of user) { // ❌ 报错!
  console.log(val);
}
// TypeError: user is not iterable

解决方案:用 Object.values() / Object.entries()

for (const val of Object.values(user)) {
  console.log(val); // 输出:我
}

4. 对比总结

特性for...infor...of
适用对象普通对象(会遍历原型链)可迭代对象(Array、Map、Set等)
返回值键名(key)值(value)
顺序保证❌ 不保证顺序(尤其数字键)✅ 保证顺序
原型链问题可能遍历到继承属性(需过滤)不会遍历原型链
适用场景遍历对象属性遍历数组、字符串等

5. 最佳实践

✅ 用 for...in 时:

  • 一定要加 hasOwnProperty 检查,避免原型链污染
  • 不要用于数组(顺序不可控,可能遍历到非数字键)

✅ 用 for...of 时:

  • 优先用于数组、字符串、Map、Set
  • 普通对象先用 Object.keys() / Object.values() 转换

6. 终极选择指南

场景推荐方式
遍历对象属性for...in + hasOwnProperty
遍历数组值for...of
遍历字符串字符for...of
遍历Map/Setfor...of
需要索引的数组遍历for 循环 或 forEach

7. 总结

  • for...in → 遍历对象属性(小心原型链)
  • for...of → 遍历可迭代对象的值(数组、字符串等)
  • 普通对象想用 for...of  先用 Object.keys() / Object.values() 转换

🚀 现在你彻底搞懂了吧?下次写循环时别再选错了!

你在使用 for...in 或 for...of 时踩过什么坑?欢迎评论区分享!  👇