 JS中可迭代的数据类型
JS中可迭代的数据类型
  # JavaScript 可迭代数据类型详解:掌握 for...of 的奥秘
在 JavaScript 中,可迭代对象是指实现了 可迭代协议 的对象,它们可以使用 for...of 循环进行遍历。理解哪些数据类型是可迭代的,对于编写高效、现代的 JavaScript 代码至关重要。
# 什么是可迭代对象?
可迭代对象必须实现 Symbol.iterator 方法,该方法返回一个迭代器对象。迭代器对象有一个 next() 方法,每次调用返回一个包含 value 和 done 属性的对象。
const iterable = {
   {
    let step = 0;
    return {
      next() {
        step++;
        if (step <= 3) {
          return { value: step, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};
for (const value of iterable) {
  console.log(value); // 1, 2, 3
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# JavaScript 内置的可迭代数据类型
# 1. Array(数组)✅
数组是最常见的可迭代对象:
const fruits = ['🍎', '🍌', '🍊'];
for (const fruit of fruits) {
  console.log(fruit); // 🍎, 🍌, 🍊
}
1
2
3
4
2
3
4
# 2. String(字符串)✅
字符串也是可迭代的,会逐个返回字符:
const greeting = 'Hello';
for (const char of greeting) {
  console.log(char); // H, e, l, l, o
}
1
2
3
4
2
3
4
# 3. Map ✅
Map 对象在迭代时会返回 [key, value] 对:
const userMap = new Map([
  ['name', 'Alice'],
  ['age', 30]
]);
for (const [key, value] of userMap) {
  console.log(`${key}: ${value}`);
}
// 输出:
// name: Alice
// age: 30
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 4. Set ✅
Set 对象迭代时返回集合中的每个值:
const uniqueNumbers = new Set([1, 2, 2, 3]);
for (const num of uniqueNumbers) {
  console.log(num); // 1, 2, 3
}
1
2
3
4
2
3
4
# 5. TypedArray(类型化数组)✅
如 Int8Array, Uint8Array 等:
const intArray = new Int8Array([10, 20, 30]);
for (const num of intArray) {
  console.log(num); // 10, 20, 30
}
1
2
3
4
2
3
4
# 6. Arguments 对象 ✅
函数内部的 arguments 对象是可迭代的:
function sum() {
  let total = 0;
  for (const arg of arguments) {
    total += arg;
  }
  return total;
}
console.log(sum(1, 2, 3)); // 6
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 7. DOM 集合 ✅
许多 DOM 集合是可迭代的:
// 获取所有 div 元素
const divs = document.querySelectorAll('div');
// 使用 for...of 遍历
for (const div of divs) {
  console.log(div);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 8. Generator 对象 ✅
生成器函数返回的对象是可迭代的:
function* generateSequence() {
  yield 1;
  yield 2;
  yield 3;
}
for (const value of generateSequence()) {
  console.log(value); // 1, 2, 3
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 不可迭代的数据类型
# 1. Object(普通对象)❌
普通对象默认不可迭代:
const person = { name: 'Alice', age: 30 };
// 会报错: person is not iterable
for (const key of person) {
  console.log(key);
}
1
2
3
4
5
6
2
3
4
5
6
# 2. WeakMap 和 WeakSet ❌
这些弱引用集合不可迭代:
const weakMap = new WeakMap();
weakMap.set({}, 'value');
// 报错: weakMap is not iterable
for (const entry of weakMap) {
  console.log(entry);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 如何使普通对象可迭代
虽然普通对象默认不可迭代,但我们可以使其可迭代:
const person = {
  name: 'Alice',
  age: 30,
  job: 'Developer',
   {
    const keys = Object.keys(this);
    let index = 0;
    
    return {
      next: () => {
        if (index < keys.length) {
          const key = keys[index++];
          return { value: [key, this[key]], done: false };
        }
        return { done: true };
      }
    };
  }
};
for (const [key, value] of person) {
  console.log(`${key}: ${value}`);
}
// 输出:
// name: Alice
// age: 30
// job: Developer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# for...of 与 for...in 的区别
| 特性 | for...of | for...in | 
|---|---|---|
| 用途 | 遍历可迭代对象的值 | 遍历对象的可枚举属性 | 
| 返回值 | 值 | 键/属性名 | 
| 原型链 | 不遍历原型链 | 遍历原型链上的可枚举属性 | 
| 适用对象 | 可迭代对象 | 所有对象 | 
| 数组遍历 | 值 | 索引 | 
| 顺序 | 保持插入顺序 | 不保证顺序(虽然通常按插入顺序) | 
# 实际应用场景
# 1. 遍历 Map 的键值对
const settings = new Map([
  ['theme', 'dark'],
  ['fontSize', 16],
  ['notifications', true]
]);
for (const [key, value] of settings) {
  console.log(`Setting ${key} is set to ${value}`);
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 2. 处理字符串中的字符
function countVowels(str) {
  const vowels = 'aeiouAEIOU';
  let count = 0;
  
  for (const char of str) {
    if (vowels.includes(char)) count++;
  }
  
  return count;
}
console.log(countVowels('Hello World')); // 3
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 3. 自定义数据结构的迭代
class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }
  
  * {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
}
const range = new Range(1, 5);
for (const num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4. 异步迭代
ES2018 引入了异步迭代器,可以与 for await...of 一起使用:
async function fetchUrls(urls) {
  for await (const response of fetchMultiple(urls)) {
    console.log(await response.text());
  }
}
async function* fetchMultiple(urls) {
  for (const url of urls) {
    yield fetch(url);
  }
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 常见问题解答
# Q: 如何判断一个对象是否可迭代?
function isIterable(obj) {
  return obj != null && typeof obj[Symbol.iterator] === 'function';
}
console.log(isIterable([])); // true
console.log(isIterable({})); // false
1
2
3
4
5
6
2
3
4
5
6
# Q: 为什么普通对象不可迭代?
- 历史原因:ES6 之前没有迭代协议
- 设计选择:对象属性的迭代顺序不确定
- 替代方案:使用 Object.keys(),Object.values(),Object.entries()
# Q: 如何遍历对象的键值对?
const person = { name: 'Alice', age: 30 };
// 使用 Object.entries 转换为可迭代的键值对数组
for (const [key, value] of Object.entries(person)) {
  console.log(`${key}: ${value}`);
}
1
2
3
4
5
6
2
3
4
5
6
# Q: for...of 可以用于 NodeList 吗?
是的,NodeList 是可迭代的:
const buttons = document.querySelectorAll('button');
for (const button of buttons) {
  button.addEventListener('click', handleClick);
}
1
2
3
4
2
3
4
# 总结
JavaScript 中可迭代的数据类型包括:
- Array
- String
- Map
- Set
- TypedArray
- Arguments对象
- DOM集合
- Generator对象
不可迭代的数据类型包括:
- 普通 Object
- WeakMap
- WeakSet
掌握这些可迭代类型及其使用场景,可以让你:
- 编写更简洁、更现代的代码
- 更好地处理集合数据
- 创建自定义的可迭代数据结构
- 利用迭代协议实现更高级的功能
for...of 循环是处理可迭代对象的强大工具,它提供了比传统 for 循环更简洁、更安全的语法,同时避免了 for...in 循环的一些陷阱。
编辑  (opens new window)
  上次更新: 2025/08/07, 01:44:52
