作为前端开发者,遍历数据是我们日常开发中高频又基础的操作。在JavaScript里,for in 和 for of 是两个极易混淆的遍历语法,不少新手甚至会在实际开发中用错场景,导致隐藏的bug。今天就用最通俗易懂的例子,帮你彻底分清这两个遍历工具的用法和区别。
一、for in 循环:遍历对象的“属性名钥匙”
for in 最初设计的核心目的是遍历对象的可枚举属性(包括原型链上的属性),它遍历的是属性名(键),而非属性值。
1. 遍历普通对象(最适合的场景)
// 定义一个博客作者对象
const blogAuthor = {
name: "前端小匠",
age: 28,
profession: "前端开发",
writeArticle: function() {
console.log("正在撰写JS教程~");
}
};
// 使用for in遍历对象
for (const key in blogAuthor) {
console.log(`属性名:${key},属性值:${blogAuthor[key]}`);
}
输出结果:
属性名:name,属性值:前端小匠
属性名:age,属性值:28
属性名:profession,属性值:前端开发
属性名:writeArticle,属性值:function() { console.log("正在撰写JS教程~"); }
2. 遍历数组(不推荐!有坑)
虽然for in也能遍历数组,但它遍历的是数组的索引(字符串类型),而非数组元素,还可能遍历到数组原型上的自定义属性:
// 定义一个博客标签数组
const blogTags = ["JavaScript", "前端", "遍历"];
// 给数组原型加一个自定义属性(模拟污染场景)
Array.prototype.author = "前端小匠";
// 使用for in遍历数组
for (const index in blogTags) {
console.log(`索引:${index}(类型:${typeof index}),值:${blogTags[index]}`);
}
输出结果:
索引:0(类型:string),值:JavaScript
索引:1(类型:string),值:前端
索引:2(类型:string),值:遍历
索引:author(类型:string),值:前端小匠 // 意外遍历到原型属性!
⚠️ 坑点总结:
– 索引是字符串类型,而非数字
– 会遍历到原型链上的属性,造成数据污染
– 遍历顺序可能不固定(尤其当数组索引不连续时)
3. for in 核心特点
- 遍历的是属性名/索引(字符串类型)
- 会遍历对象原型链上的可枚举属性
- 主要用于遍历普通对象,不推荐遍历数组
- 可以通过
hasOwnProperty()过滤原型属性:for (const key in blogAuthor) { if (blogAuthor.hasOwnProperty(key)) { // 只遍历自身属性 console.log(key, blogAuthor[key]); } }
二、for of 循环:遍历可迭代对象的“值”
ES6推出的for of 专门解决了for in的痛点,它的核心是遍历可迭代对象的“值”,支持数组、字符串、Set、Map等可迭代类型,不能直接遍历普通对象。
1. 遍历数组(最常用的场景)
// 博客阅读量数组
const readCounts = [1000, 2500, 800];
// 使用for of遍历数组
for (const count of readCounts) {
console.log(`阅读量:${count}`);
}
输出结果:
阅读量:1000
阅读量:2500
阅读量:800
✅ 优势:直接拿到数组元素值,无需通过索引取值,代码更简洁。
2. 遍历字符串
// 博客标题字符串
const blogTitle = "JS遍历教程";
for (const char of blogTitle) {
console.log(char);
}
输出结果:
J
S
遍
历
教
程
3. 遍历Set/Map(天然适配)
// 遍历Set(博客标签去重)
const uniqueTags = new Set(["JS", "前端", "JS", "遍历"]);
for (const tag of uniqueTags) {
console.log("Set元素:", tag);
}
// 遍历Map(博客评论)
const blogComments = new Map([
["用户1", "写得太赞了!"],
["用户2", "终于分清for in和for of了~"]
]);
for (const [username, comment] of blogComments) {
console.log(`${username}:${comment}`);
}
输出结果:
Set元素: JS
Set元素: 前端
Set元素: 遍历
用户1:写得太赞了!
用户2:终于分清for in和for of了~
4. 遍历普通对象(需要转换)
for of 不能直接遍历普通对象,但可以通过 Object.keys()/Object.values()/Object.entries() 转换后遍历:
const blogAuthor = {
name: "前端小匠",
age: 28
};
// 遍历属性值
for (const value of Object.values(blogAuthor)) {
console.log("属性值:", value);
}
// 同时遍历属性名和值
for (const [key, value] of Object.entries(blogAuthor)) {
console.log(`${key}:${value}`);
}
输出结果:
属性值: 前端小匠
属性值: 28
name:前端小匠
age:28
5. for of 核心特点
- 遍历的是值,而非键/索引
- 只遍历自身数据,不会遍历原型链
- 支持
break/continue/return中断循环 - 只能遍历可迭代对象(数组、字符串、Set、Map等),普通对象需转换
三、for in vs for of 核心区别对比
| 特性 | for in | for of |
|---|---|---|
| 遍历目标 | 所有可枚举属性(含原型) | 可迭代对象的元素值 |
| 遍历内容 | 属性名/索引(字符串) | 元素值 |
| 适用场景 | 遍历普通对象 | 遍历数组、字符串、Set、Map等 |
| 是否遍历原型属性 | 是(需手动过滤) | 否 |
| 是否支持中断循环 | 是 | 是 |
| 能否遍历普通对象 | 能 | 需转换(Object.entries等) |
总结
- for in 主打遍历普通对象的属性名,遍历数组有坑,需谨慎使用,遍历原型属性时记得用
hasOwnProperty()过滤; - for of 主打遍历可迭代对象(数组、字符串、Set/Map)的元素值,代码更简洁,是遍历数组的首选;
- 核心原则:遍历对象用
for in,遍历数组/字符串等可迭代对象用for of。
记住这个简单的原则,你就能在开发中精准选择合适的遍历方式,避开不必要的坑啦~





