0

0

JS如何实现迭代协议?可迭代对象

小老鼠

小老鼠

发布时间:2025-08-23 11:54:02

|

398人浏览过

|

来源于php中文网

原创

JavaScript迭代协议通过Symbol.iterator让对象可迭代,实现该方法并返回带next()的迭代器对象,即可用for...of或展开运算符遍历;生成器函数(function*)配合yield能更简洁地创建迭代器,自动管理状态与next()逻辑,提升代码可读性与灵活性。

js如何实现迭代协议?可迭代对象

JavaScript中的迭代协议,说白了,就是一套约定,它让任何对象都能定义自己的遍历行为。核心在于实现一个特定的方法:

[Symbol.iterator]
。只要一个对象有这个方法,并且这个方法能返回一个符合迭代器协议的对象,那它就是“可迭代对象”。这意味着你可以用
for...of
循环它,或者用展开运算符(
...
)来解构它,就像处理数组一样。这套机制让数据消费变得非常统一和灵活。

迭代协议的实现机制

要让一个JavaScript对象变得可迭代,你需要给它添加一个名为

[Symbol.iterator]
的方法。这个方法必须是一个函数,并且它被调用时,必须返回一个“迭代器”对象。

那么,什么是迭代器呢?迭代器本身也是一个对象,它必须包含一个

next()
方法。每次调用这个
next()
方法时,它都应该返回一个包含两个属性的对象:

  • value
    : 这是当前迭代到的值。
  • done
    : 这是一个布尔值,表示迭代是否已经完成。如果迭代结束,
    done
    就应该是
    true
    ;否则,就是
    false

举个例子,假设我们想创建一个简单的计数器,让它能从某个数字开始,数到另一个数字:

function createCounter(start, end) {
  let current = start;
  return {
    [Symbol.iterator]() { // 这就是可迭代协议的关键
      return { // 返回一个迭代器对象
        next() { // 迭代器对象必须有next方法
          if (current <= end) {
            return { value: current++, done: false };
          } else {
            return { value: undefined, done: true };
          }
        }
      };
    }
  };
}

const myCounter = createCounter(1, 3);

for (const num of myCounter) {
  console.log(num); // 输出 1, 2, 3
}

// 也可以用展开运算符
const numsArray = [...createCounter(5, 7)];
console.log(numsArray); // 输出 [5, 6, 7]

这里可以看到,

createCounter
返回的对象就是可迭代的,因为它实现了
[Symbol.iterator]
。而
[Symbol.iterator]
方法返回的那个带有
next()
的对象,就是迭代器。这种分离的设计很常见,让你可以控制迭代的状态。

for...of
循环是如何与迭代协议协同工作的?

for...of
循环是ES6引入的,它专门用来遍历可迭代对象。它的工作原理其实非常直接,但又很巧妙。当你写下
for (const item of someIterableObject)
时,JavaScript引擎在幕后做了几件事:

它会首先尝试调用

someIterableObject
[Symbol.iterator]()
方法。如果这个方法不存在,或者返回的不是一个迭代器对象,那么就会抛出一个错误,告诉你这个对象不是可迭代的。

Magic AI Avatars
Magic AI Avatars

神奇的AI头像,获得200多个由AI制作的自定义头像。

下载

如果成功获取到迭代器,

for...of
就会反复调用这个迭代器的
next()
方法。每次调用,它都会检查
next()
返回的对象中的
done
属性。

  • 如果
    done
    false
    ,那么
    value
    属性的值就会被赋给
    item
    变量,然后循环体内的代码会被执行。
  • 如果
    done
    true
    ,这意味着迭代已经完成,
    for...of
    循环就会终止。

这与传统的

for...in
循环形成鲜明对比。
for...in
是用来遍历对象属性名的,它会枚举对象自身以及原型链上的可枚举属性。而
for...of
则完全聚焦于数据集合的“值”本身,它不关心属性名,只关心通过迭代协议暴露出来的数据序列。这使得
for...of
在处理数组、字符串、Map、Set以及你自定义的任何可迭代数据结构时,都能提供一种统一且直观的遍历方式。在我看来,这是现代JavaScript中处理数据流非常基础且强大的一个抽象。

如何利用生成器函数更简洁地创建可迭代对象?

手动实现迭代器的

next()
方法,尤其是当迭代逻辑比较复杂时,可能会显得有些冗长和容易出错。JavaScript为此提供了一个语法糖,也就是“生成器函数”(Generator Function),它能极大地简化可迭代对象的创建过程。

生成器函数使用

function*
语法定义,并且在函数体内部,你可以使用
yield
关键字来“产出”值。每次
yield
一个值,生成器函数就会暂停执行,并返回这个值作为迭代器结果的
value
,同时
done
会被自动设为
false
。当再次调用迭代器的
next()
方法时,生成器函数会从上次暂停的地方继续执行,直到遇到下一个
yield
或函数结束。如果函数执行完毕(没有更多的
yield
),那么返回的
done
就会是
true

这意味着,一个生成器函数本身在被调用时,就会返回一个迭代器对象,这个对象已经自动实现了

next()
方法。所以,要创建一个可迭代对象,你只需要让它的
[Symbol.iterator]
方法是一个生成器函数即可。

// 还是那个计数器,用生成器函数实现
function createCounterWithGenerator(start, end) {
  return {
    [Symbol.iterator]: function* () { // [Symbol.iterator] 现在是一个生成器函数
      for (let i = start; i <= end; i++) {
        yield i; // 每次yield一个值,就会暂停并返回
      }
    }
  };
}

const myGenCounter = createCounterWithGenerator(10, 12);

for (const num of myGenCounter) {
  console.log(num); // 输出 10, 11, 12
}

// 或者更直接地,生成器函数本身就是迭代器
function* simpleGenerator() {
  yield 'Hello';
  yield 'World';
  yield '!';
}

const gen = simpleGenerator(); // 调用生成器函数直接返回一个迭代器
console.log(gen.next()); // { value: 'Hello', done: false }
console.log(gen.next()); // { value: 'World', done: false }
console.log(gen.next()); // { value: '!', done: false }
console.log(gen.next()); // { value: undefined, done: true }

// 甚至可以直接用for...of遍历生成器函数返回的迭代器
for (const item of simpleGenerator()) {
    console.log(item); // 输出 Hello, World, !
}

在我看来,生成器函数简直是迭代器协议的“最佳拍档”。它把复杂的迭代逻辑,特别是那些需要维护内部状态的遍历,用一种更接近同步代码的直观方式表达出来。你不再需要手动管理

value
done
yield
关键字和生成器函数的执行流程帮你把这些都处理好了。这不仅提升了代码的可读性,也大大降低了实现自定义迭代器的心智负担。当你需要处理任何形式的数据流,无论是从文件读取、网络请求分块,还是简单的数字序列,生成器函数都能提供一种非常优雅的解决方案。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
es6新特性
es6新特性

es6新特性有:1、块级作用域变量;2、箭头函数;3、模板字符串;4、解构赋值;5、默认参数;6、 扩展运算符;7、 类和继承;8、Promise。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

106

2023.07.17

es6新特性有哪些
es6新特性有哪些

es6的新特性有:1、块级作用域;2、箭头函数;3、解构赋值;4、默认参数;5、扩展运算符;6、模板字符串;7、类和模块;8、迭代器和生成器;9、Promise对象;10、模块化导入和导出等等。本专题为大家提供es6新特性的相关的文章、下载、课程内容,供大家免费下载体验。

197

2023.08.04

JavaScript ES6新特性
JavaScript ES6新特性

ES6是JavaScript的根本性升级,引入let/const实现块级作用域、箭头函数解决this绑定问题、解构赋值与模板字符串简化数据处理、对象简写与模块化提升代码可读性与组织性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

233

2025.12.24

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1567

2023.10.24

Go语言中的运算符有哪些
Go语言中的运算符有哪些

Go语言中的运算符有:1、加法运算符;2、减法运算符;3、乘法运算符;4、除法运算符;5、取余运算符;6、比较运算符;7、位运算符;8、按位与运算符;9、按位或运算符;10、按位异或运算符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

241

2024.02.23

php三元运算符用法
php三元运算符用法

本专题整合了php三元运算符相关教程,阅读专题下面的文章了解更多详细内容。

150

2025.10.17

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

562

2023.09.20

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号