for...of 是 ES6 引入的迭代循环语法,专门用于遍历可迭代对象(Iterable),语法简洁、语义清晰,避免了传统 for 循环的索引冗余和 for...in 的原型链污染问题。
一、核心概念:可迭代对象
for...of 只能遍历可迭代对象,即部署了 [Symbol.iterator] 方法的对象。JavaScript 中默认支持的可迭代对象包括:
- 数组(Array)
- 字符串(String)
- 集合(Set)
- 映射(Map)
- 类数组对象(如
arguments、DOM 集合NodeList) - Generator 对象
二、基本语法
for (const 变量 of 可迭代对象) {
// 循环体:变量每次迭代对应对象的一个元素
}
变量:接收每次迭代的元素值(而非索引,与for...in不同)。- 建议用
const(元素不可修改),若需修改元素(如数组元素),可用let。
三、常见使用场景
1. 遍历数组(最常用)
直接获取数组元素,无需索引:
const arr = ['a', 'b', 'c'];
for (const item of arr) {
console.log(item); // 输出:a、b、c
}
// 需修改元素时用 let
const nums = [1, 2, 3];
for (let num of nums) {
num *= 2; // 修改循环变量(不影响原数组,因是值类型)
console.log(num); // 2、4、6
}
console.log(nums); // [1,2,3](原数组未变)
// 若需修改原数组,需结合索引(可用 Array.prototype.entries())
for (const [index, num] of nums.entries()) {
nums[index] = num * 2; // 通过索引修改原数组
}
console.log(nums); // [2,4,6]
2. 遍历字符串
字符串按字符迭代(含 Unicode 字符,如中文、表情):
const str = 'hello世界😀';
for (const char of str) {
console.log(char); // 输出:h、e、l、l、o、世、界、😀
}
3. 遍历 Set
Set 无重复元素,迭代时直接获取元素值:
const set = new Set([1, 2, 2, 3]);
for (const val of set) {
console.log(val); // 输出:1、2、3(自动去重)
}
4. 遍历 Map
Map 迭代时返回 [key, value] 数组,需解构获取键值:
const map = new Map([
['name', '张三'],
['age', 20]
]);
for (const [key, value] of map) {
console.log(`${key}: ${value}`); // 输出:name: 张三、age: 20
}
// 单独遍历键/值
for (const key of map.keys()) { /* ... */ }
for (const value of map.values()) { /* ... */ }
5. 遍历类数组对象
如 NodeList(DOM 元素集合)、arguments:
// 遍历 DOM 元素(NodeList)
const lis = document.querySelectorAll('li');
for (const li of lis) {
li.style.color = 'red'; // 批量修改样式
}
// 遍历 arguments(函数参数集合)
function sum() {
let total = 0;
for (const num of arguments) {
total += num;
}
return total;
}
console.log(sum(1,2,3)); // 6
6. 遍历 Generator 对象
Generator 是专门的迭代器生成函数,配合 for...of 自动迭代:
function* generator() {
yield 1;
yield 2;
yield 3;
}
for (const val of generator()) {
console.log(val); // 输出:1、2、3
}
四、for...of 与 for...in 的区别(关键!)
| 特性 | for...of | for...in |
|---|---|---|
| 遍历目标 | 元素值(可迭代对象) | 索引 / 属性名(对象) |
| 适用对象 | 数组、字符串、Set、Map 等可迭代对象 | 任意对象(含数组、普通对象) |
| 原型链属性 | 不遍历(仅自身可迭代元素) | 会遍历原型链上的可枚举属性 |
| 数组空位(empty) | 跳过空位(不处理) | 视为 undefined(遍历空位索引) |
反例:for...in 遍历数组的问题:
const arr = [1, 2, 3];
// 给数组原型添加属性(污染)
Array.prototype.test = '原型属性';
for (const key in arr) {
console.log(key); // 输出:0、1、2、test(遍历了原型属性)
}
for (const val of arr) {
console.log(val); // 输出:1、2、3(忽略原型属性)
}
五、中断 for...of 循环
支持 break、continue、return(函数内)中断循环,与普通 for 循环一致:
const arr = [1, 2, 3, 4, 5];
for (const val of arr) {
if (val === 3) break; // 遇到 3 终止循环
console.log(val); // 输出:1、2
}
for (const val of arr) {
if (val % 2 === 0) continue; // 跳过偶数
console.log(val); // 输出:1、3、5
}
六、自定义可迭代对象(进阶)
若想让普通对象支持 for...of,需手动部署 [Symbol.iterator] 方法:
const obj = {
name: '张三',
age: 20,
hobbies: ['篮球', '游戏'],
// 部署迭代器方法
[Symbol.iterator]() {
let index = 0;
const hobbies = this.hobbies;
// 返回迭代器对象(含 next() 方法)
return {
next() {
if (index < hobbies.length) {
return { value: hobbies[index++], done: false }; // 未结束
} else {
return { value: undefined, done: true }; // 已结束
}
}
};
}
};
// 现在 obj 可被 for...of 遍历(遍历 hobbies 数组)
for (const hobby of obj) {
console.log(hobby); // 输出:篮球、游戏
}
总结
for...of 是遍历可迭代对象的最优选择:
- 语法简洁,直接获取元素值,无需处理索引;
- 避免
for...in的原型链污染问题; - 支持所有常见数据结构(数组、字符串、Set、Map 等);
- 可灵活中断循环。
日常开发中,优先用 for...of 遍历数组、字符串、集合等,仅在需要遍历普通对象的属性时考虑 for...in(或 Object.keys())。

703

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



