一文详解JavaScrip可迭代对象(Iterable)

 更新时间:2026年05月12日 08:50:13   作者:yqcoder  
本文解释了ES6引入迭代器和可迭代对象的原因及使用方法,通过引入这两个概念,JavaScript 统一了数据访问接口,解决了遍历方式不统一和灵活性差的问题,文章详细介绍了核心概念、底层原理、实战案例、常见误区及最佳实践,帮助读者彻底理解可迭代对象,需要的朋友可以参考下

为什么需要“可迭代”?

在 ES6 之前,我们遍历数据主要靠 for 循环(基于索引)或 forEach。但这种方式有两个痛点:

  1. 不通用:数组能遍历,但字符串、DOM 节点列表、Map、Set 的遍历方式各不相同。
  2. 不灵活:无法自定义遍历逻辑(比如我想倒序遍历,或者只遍历偶数项)。

为了解决这个问题,ES6 引入了 迭代器 (Iterator)可迭代对象 (Iterable) 的概念,统一了数据访问的接口。

通俗比喻
想象你去一家自助餐厅吃饭。

  • 普通对象:像是一堆散落在桌子上的菜,没有顺序,你只能指着说“我要那个”,不能按顺序一个个拿。
  • 可迭代对象:像是传送带上的寿司。传送带有一个机制(迭代器),让你可以一个一个地按顺序获取食物,直到吃完为止。

Symbol.iterator 就是那个“启动传送带的按钮”。只要一个对象身上有这个按钮,它就是“可迭代的”。

1. 核心概念:谁是谁?

很多初学者容易混淆这两个术语,我们先厘清定义:

可迭代对象 (Iterable)

  • 定义:实现了 可迭代协议 的对象。
  • 特征:对象内部必须有一个键为 Symbol.iterator 的方法,该方法返回一个迭代器对象
  • 常见例子Array, String, Map, Set, arguments, NodeList

迭代器 (Iterator)

  • 定义:实现了 迭代器协议 的对象。
  • 特征:拥有一个 next() 方法,每次调用返回一个包含 valuedone 的对象。
  • 作用:它是真正的“工人”,负责逐个吐出数据。

简单关系
可迭代对象 是工厂,迭代器 是工厂派出的快递员。
当你使用 for...of 时,JS 引擎会自动调用工厂的 Symbol.iterator 拿到快递员,然后一直喊 next() 直到送完货。

2. 底层原理:两个协议

协议一:可迭代协议 (Iterable Protocol)

只要对象拥有 [@@iterator] 方法(即 Symbol.iterator 属性),它就是可迭代的。

const arr = [1, 2, 3];
// 检查是否有 Symbol.iterator 方法
console.log(typeof arr[Symbol.iterator]); // "function"

协议二:迭代器协议 (Iterator Protocol)

Symbol.iterator 方法返回的对象,必须满足以下条件:

  1. 拥有 next() 方法。
  2. next() 返回一个对象 { value: any, done: boolean }
    • value: 当前产出的值。
    • done: 是否遍历结束(true 表示结束)。

3. 代码实战:判断与使用

场景一:哪些是原生的可迭代对象?

// ✅ 数组
[1, 2, 3][Symbol.iterator]; // function

// ✅ 字符串
"hello"[Symbol.iterator]; // function

// ✅ Map
new Map()[Symbol.iterator](
  // function

  // ❌ 普通对象
  {},
)[Symbol.iterator]; // undefined -> 不可迭代!

场景二:for...of的本质

当你写这段代码时:

for (const item of [1, 2, 3]) {
  console.log(item);
}

JavaScript 引擎实际上在执行以下操作:

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator](); // 1. 获取迭代器

let result = iterator.next(); // 2. 第一次 next()
while (!result.done) {
  // 3. 如果没做完
  console.log(result.value); // 4. 处理值
  result = iterator.next(); // 5. 继续下一个
}

4. 手写实现:让普通对象可迭代

这是面试的高频考点:如何让一个普通对象支持 for...of

假设我们有一个范围对象 Range,我们希望它能遍历出从 startend 的数字。

const range = {
  start: 1,
  end: 5,
};

// ❌ 直接遍历会报错:range is not iterable
// for (let num of range) { ... }

// ✅ 改造:添加 Symbol.iterator 方法
range[Symbol.iterator] = function () {
  let current = this.start;
  const last = this.end;

  // 返回一个符合“迭代器协议”的对象
  return {
    next() {
      if (current <= last) {
        return { value: current++, done: false };
      } else {
        return { value: undefined, done: true };
      }
    },
  };
};

// 现在可以愉快地遍历了!
for (let num of range) {
  console.log(num); // 1, 2, 3, 4, 5
}

// 也可以使用展开运算符
console.log([...range]); // [1, 2, 3, 4, 5]

关键点
Symbol.iterator 函数必须返回一个的迭代器对象。这样即使嵌套遍历或多次遍历,状态也不会冲突。

5. 常见误区:Array-like vs Iterable

很多“类数组对象”(Array-like)不是可迭代对象,这经常导致 Bug。

误区:arguments和NodeList

在旧版浏览器或某些环境下,document.querySelectorAll 返回的 NodeList 可能没有 Symbol.iterator(虽然现代浏览器大多已支持,但需警惕兼容性)。

const divs = document.querySelectorAll("div");

// ❌ 在某些旧环境或特定对象上可能失效
// for (let div of divs) { ... }

// ✅ 安全做法:使用 Array.from 转换
const divArray = Array.from(divs);
divArray.forEach((div) => console.log(div));

最佳实践:如何安全地遍历?

如果你不确定一个对象是否可迭代,可以使用以下工具函数检测:

function isIterable(obj) {
  // 检查 null/undefined
  if (obj == null) return false;
  // 检查是否有 Symbol.iterator 方法且类型为函数
  return typeof obj[Symbol.iterator] === "function";
}

console.log(isIterable([])); // true
console.log(isIterable({})); // false
console.log(isIterable("")); // true

6. 总结

概念说明关键方法/属性
可迭代对象能被 for...of 遍历的对象obj[Symbol.iterator]
迭代器负责逐个返回数据的对象iterator.next()
next() 返回值包含值和状态的对象{ value: ..., done: ... }
原生可迭代Array, String, Map, Set, arguments 等-
非可迭代普通 Object {}-

博主寄语
可迭代协议是 JavaScript 统一数据访问方式的伟大尝试。
它不仅让 for...of 成为可能,还支撑起了生成器 (Generator)、异步迭代器 (Async Iterator) 等高级特性。

记住口诀
想要遍历用 for...of
对象必须有 iterator
next 方法吐数据,
done 为真停脚步。

以上就是一文详解JavaScrip可迭代对象(Iterable)的详细内容,更多关于JavaScrip可迭代对象Iterable的资料请关注脚本之家其它相关文章!

相关文章

  • javascript中import和export用法示例总结

    javascript中import和export用法示例总结

    在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种,前者用于服务器,后者用于浏览器,这篇文章给大家介绍了javascript中import和export用法总结,感兴趣的朋友一起看看吧
    2025-05-05
  • JS的反射问题

    JS的反射问题

    两个等号直接比较值,但是类型不能相互转换的时候报错
    2010-04-04
  • 点击弹出层效果&弹出窗口后网页背景变暗效果的实现代码

    点击弹出层效果&弹出窗口后网页背景变暗效果的实现代码

    本篇文章主要是对点击弹出层效果&弹出窗口后网页背景变暗效果的实现代码进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2014-02-02
  • Web纯前端“旭日图”实现元素周期表

    Web纯前端“旭日图”实现元素周期表

    本文主要介绍了Web纯前端“旭日图”实现元素周期表的实例解析。具有很好的参考价值。下面跟着小编一起来看下吧
    2017-03-03
  • javascript中的some方法使用解读

    javascript中的some方法使用解读

    这篇文章主要介绍了javascript中的some方法使用解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • JavaScript实现Tab选项卡切换

    JavaScript实现Tab选项卡切换

    这篇文章主要为大家详细介绍了JavaScript实现Tab选项卡切换效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • jquery+css3实现网页背景花瓣随机飘落特效

    jquery+css3实现网页背景花瓣随机飘落特效

    在qq空间可以自定义一些插件,装饰空间,大家通常就是复制代码到空间粘贴,会实现非常美观的效果,有的会随机飘落一些花瓣,那么这种效果用代码怎么实现的呢,下面小编给大家详解jquery实现网页背景花瓣随机飘落特效,需要的朋友可以参考下
    2015-08-08
  • 微信小程序学习笔记之目录结构、基本配置图文详解

    微信小程序学习笔记之目录结构、基本配置图文详解

    这篇文章主要介绍了微信小程序学习笔记之目录结构、基本配置,结合实例形式详细分析了微信小程序的相关注册、配置及基本使用方法,并配以图片加以说明,需要的朋友可以参考下
    2019-03-03
  • JavaScript TAB栏切换效果的示例

    JavaScript TAB栏切换效果的示例

    这篇文章主要介绍了JavaScript TAB栏切换效果的示例,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下
    2020-11-11
  • 读懂CommonJS的模块加载

    读懂CommonJS的模块加载

    这篇文章主要介绍了CommonJS的模块加载,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04

最新评论