ES6 迭代器 (`Iterator`)使用总结

Iterator(迭代器)是 ES6 引入的一种 接口,用于 顺序访问 可迭代对象ArraySetMapStringarguments、自定义对象等)。
Iterator(迭代器)的作用有三个:

  1. 为各种数据结构提供一个统一的、简便的访问接口
  2. 使数据结构的成员能够按某种次序排列
  3. ES6 创造了一种新的遍历命令 for…of 循环,Iterator 接口主要供 for…of 消费

1. 迭代器的基本概念

(1) 迭代器是什么?

  • 迭代器是一种 特殊对象,提供 next() 方法,每次调用都会返回:
    { value: 当前值, done: 是否完成 }
    
  • done: true 时,表示迭代结束。

Iterator 的遍历过程

// Iterator 的遍历过程如下:
1. 创建一个指针对象,指向当前数据结构的起始位置
2. 第一次调用指针对象的 next 方法,可以将指针指向数据结构的第一个成员
3. 第二次调用指针对象的 next 方法,指针就指向数据结构的第二个成员
4. 不断调用指针对象的 next 方法,直到它指向数据结构的结束位置

// 每一次调用 next 方法,都会返回一个包含 value 和 done 两个属性的对象
{
  value: 当前成员的值,
  done: 布尔值,表示遍历是否结束
}

2. 生成迭代器

(1) 手动创建迭代器

function createIterator(arr) {
  let index = 0;
  return {
    next: function () {
      return index < arr.length
        ? { value: arr[index++], done: false }
        : { value: undefined, done: true };
    }
  };
}

let iterator = createIterator(["a", "b", "c"]);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }

📌 每次 next() 调用,都会返回 value 并前进


(2) 使用 Symbol.iterator

所有 可迭代对象ArraySetMap 等)都有 默认的迭代器,可以用 Symbol.iterator 访问:

let arr = ["x", "y", "z"];
let iterator = arr[Symbol.iterator]();

console.log(iterator.next()); // { value: 'x', done: false }
console.log(iterator.next()); // { value: 'y', done: false }
console.log(iterator.next()); // { value: 'z', done: false }
console.log(iterator.next()); // { value: undefined, done: true }

📌 数组、字符串、Set、Map 都有 Symbol.iterator,可直接迭代


(3) 自定义对象的迭代器

普通对象没有默认迭代器,需手动实现:

let myObj = {
  data: [10, 20, 30],
  [Symbol.iterator]: function () {
    let index = 0;
    return {
      next: () => {
        return index < this.data.length
          ? { value: this.data[index++], done: false }
          : { value: undefined, done: true };
      }
    };
  }
};

let iter = myObj[Symbol.iterator]();
console.log(iter.next()); // { value: 10, done: false }
console.log(iter.next()); // { value: 20, done: false }
console.log(iter.next()); // { value: 30, done: false }
console.log(iter.next()); // { value: undefined, done: true }

📌 对象没有默认迭代器,需实现 Symbol.iterator 才能用 for...of


3. for...of 遍历迭代器

所有 实现 Symbol.iterator 的对象,都可以用 for...of 遍历:

let arr = ["A", "B", "C"];

for (let char of arr) {
  console.log(char);
}
// A
// B
// C

📌 相比 forEach()for...of 可与 breakcontinue 配合使用


4. 可迭代对象

可以使用 for...ofSymbol.iterator 的对象

  • Array
  • String
  • Set
  • Map
  • arguments
  • NodeList
  • 自定义对象(需实现 Symbol.iterator

5. SetMap 的迭代器

(1) Set 迭代

let mySet = new Set(["apple", "banana", "cherry"]);
let setIter = mySet[Symbol.iterator]();

console.log(setIter.next()); // { value: 'apple', done: false }
console.log(setIter.next()); // { value: 'banana', done: false }
console.log(setIter.next()); // { value: 'cherry', done: false }
console.log(setIter.next()); // { value: undefined, done: true }

📌 Set 按插入顺序存储,迭代返回唯一值。


(2) Map 迭代

let myMap = new Map([
  ["name", "Alice"],
  ["age", 25]
]);

for (let [key, value] of myMap) {
  console.log(key, value);
}
// name Alice
// age 25

📌 Map 迭代时返回 [key, value] 数组。


6. 迭代器 vs 生成器

特性迭代器 (Iterator)生成器 (Generator)
创建方式手动实现 next()function* 生成
使用 Symbol.iterator需要手动实现生成器自动实现
可暂停执行❌ 否✅ 是(可 yield

示例:生成器

function* generatorFunction() {
  yield "A";
  yield "B";
  yield "C";
}

let gen = generatorFunction();
console.log(gen.next()); // { value: 'A', done: false }
console.log(gen.next()); // { value: 'B', done: false }
console.log(gen.next()); // { value: 'C', done: false }
console.log(gen.next()); // { value: undefined, done: true }

📌 生成器更简洁,支持 yield 暂停执行


7. Iterator 使用场景

7.1 解构赋值

// 对数组和 Set 结构进行解构赋值时,会默认调用 Iterator 接口
let set = new Set().add('a').add('b').add('c');
let [x, y] = set; // x='a'; y='b'

7.2 扩展运算符

// 扩展运算符(...)也会调用默认的 Iterator 接口
let str = 'hello';
[...str] // ['h', 'e', 'l', 'l', 'o']

let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']

7.3 yield*

// yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口
let generator = function* () {
  yield 1;
  yield* [2, 3, 4];
  yield 5;
};

for (let v of generator()) {
  console.log(v);
}
// 1, 2, 3, 4, 5

8. 注意事项

8.1 对象的 for…of 循环

// 对象默认不具备 Iterator 接口,不能直接使用 for...of
let obj = { a: 1, b: 2, c: 3 };
for (let value of obj) {
  console.log(value); // TypeError: obj is not iterable
}

// 正确的遍历对象方式
// 1. 使用 Object.keys()
for (let key of Object.keys(obj)) {
  console.log(key + ': ' + obj[key]);
}

// 2. 使用 Object.entries()
for (let [key, value] of Object.entries(obj)) {
  console.log(key + ': ' + value);
}

8.2 Iterator 接口与 Generator 函数

// 使用 Generator 函数实现 Iterator 接口
let obj = {
  *[Symbol.iterator]() {
    yield 'hello';
    yield 'world';
  }
};

for (let x of obj) {
  console.log(x);
}
// hello
// world

9. 最佳实践

9.1 为类部署 Iterator 接口

class Collection {
  constructor() {
    this.items = [];
  }

  add(item) {
    this.items.push(item);
  }

  *[Symbol.iterator]() {
    for (let item of this.items) {
      yield item;
    }
  }
}

let collection = new Collection();
collection.add('foo');
collection.add('bar');

for (let value of collection) {
  console.log(value);
}
// foo
// bar

9.2 异步迭代器

// ES2018 引入了异步迭代器
const asyncIterable = {
  async *[Symbol.asyncIterator]() {
    yield 'hello';
    yield 'async';
    yield 'iteration';
  }
};

(async () => {
  for await (const x of asyncIterable) {
    console.log(x);
  }
})();
// hello
// async
// iteration

10. 适用场景

适用于

  1. 遍历数组、字符串、Set、Map
  2. 自定义可迭代对象
  3. 流式处理数据(类似分页加载)
  4. 避免一次性加载大数据(生成器)

11. 总结

  • Iterator 是 ES6 提供的一种接口,用于顺序访问集合。
  • Symbol.iterator 让对象变成可迭代,可用于 for...ofspread
  • SetMapArrayString 默认实现 Symbol.iterator,可直接迭代。
  • 生成器 (Generator) 自动创建迭代器,可暂停执行 (yield),更强大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966162.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习案列】糖尿病风险可视化及预测

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

单片机之基本元器件的工作原理

一、二极管 二极管的工作原理 二极管是一种由P型半导体和N型半导体结合形成的PN结器件&#xff0c;具有单向导电性。 1. PN结形成 P型半导体&#xff1a;掺入三价元素&#xff0c;形成空穴作为多数载流子。N型半导体&#xff1a;掺入五价元素&#xff0c;形成自由电子作为多…

llama.cpp GGUF 模型格式

llama.cpp GGUF 模型格式 1. Specification1.1. GGUF Naming Convention (命名规则)1.1.1. Validating Above Naming Convention 1.2. File Structure 2. Standardized key-value pairs2.1. General2.1.1. Required2.1.2. General metadata2.1.3. Source metadata 2.2. LLM2.2.…

Conmi的正确答案——Rider中添加icon作为exe的图标

C#版本&#xff1a;.net 8.0 Rider版本&#xff1a;#RD-243.22562.250&#xff08;非商业使用版&#xff09; 1、添加图标到解决方案下&#xff1a; 2、打开“App.xaml”配置文件&#xff0c;添加配置&#xff1a; <Applicationx:Class"ComTransmit.App"xmlns&q…

告别手动操作!用Ansible user模块高效管理 Linux账户

在企业运维环境中&#xff0c;服务器的用户管理是一项基础但非常重要的任务。比如&#xff0c;当有新员工加入时&#xff0c;我们需要在多台服务器上为他们创建账户并分配合适的权限。而当员工离职或岗位发生变化时&#xff0c;我们也需要迅速禁用或删除他们的账户&#xff0c;…

C++小等于的所有奇数和=最大奇数除2加1的平方。

缘由 三种思路解题&#xff1a;依据算术推导得到一个规律&#xff1a;小等于的所有奇数和等于最大奇数除以2加1的平方。将在后续发布&#xff0c;总计有十种推导出来的实现代码。 int a 0,aa 1,aaa 0;cin >> a; while (aa<a) aaa aa, aa 2;cout << aaa;i…

【CPP】CPP经典面试题

文章目录 引言1. C 基础1.1 C 中的 const 关键字1.2 C 中的 static 关键字 2. 内存管理2.1 C 中的 new 和 delete2.2 内存泄漏 3. 面向对象编程3.1 继承和多态3.2 多重继承 4. 模板和泛型编程4.1 函数模板4.2 类模板 5. STL 和标准库5.1 容器5.2 迭代器 6. 高级特性6.1 移动语义…

深入浅出谈VR(虚拟现实、VR镜头)

1、VR是什么鬼&#xff1f; 近两年VR这次词火遍网上网下&#xff0c;到底什么是VR&#xff1f;VR是“Virtual Reality”&#xff0c;中文名字是虚拟现实&#xff0c;是指采用计算机技术为核心的现代高科技手段生成一种虚拟环境&#xff0c;用户借助特殊的输入/输出设备&#x…

【Redis】安装配置Redis超详细教程 / Linux版

Linux安装配置Redis超详细教程 安装redis依赖安装redis启动redis停止redisredis.conf常见配置设置redis为后台启动修改redis监听地址设置工作目录修改密码监听的端口号数据库数量设置redis最大内存设置日志文件设置redis开机自动启动 学习视频&#xff1a;黑马程序员Redis入门到…

[LeetCode]day16 242.有效的字母异位词

242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的 字母异位词 示例 1: 输入: s "anagram", t "nagaram" 输出: true示例 2: 输入: s "rat"…

[MoeCTF 2022]baby_file

题目 <html> <title>Heres a secret. Can you find it?</title> <?phpif(isset($_GET[file])){$file $_GET[file];include($file); }else{highlight_file(__FILE__); } ?> </html> 读取flag /?filephp://filter/readconvert.base64-encode…

Centos挂载镜像制作本地yum源,并补装图形界面

内网环境centos7.9安装图形页面内网环境制作本地yum源 上传镜像到服务器目录 创建目录并挂载镜像 #创建目录 cd /mnt/ mkdir iso#挂载 mount -o loop ./CentOS-7-x86_64-DVD-2009.iso ./iso #前面镜像所在目录&#xff0c;后面所挂载得目录#检查 [rootlocalhost mnt]# df -h…

判断您的Mac当前使用的是Zsh还是Bash:echo $SHELL、echo $0

要判断您的Mac当前使用的是Zsh还是Bash&#xff0c;可以使用以下方法&#xff1a; 查看默认Shell: 打开“终端”应用程序&#xff0c;然后输入以下命令&#xff1a; echo $SHELL这将显示当前默认使用的Shell。例如&#xff0c;如果输出是/bin/zsh&#xff0c;则说明您使用的是Z…

python 小游戏:扫雷

目录 1. 前言 2. 准备工作 3. 生成雷区 4. 鼠标点击扫雷 5. 胜利 or 失败 6. 游戏效果展示 7. 完整代码 1. 前言 本文使用 Pygame 实现的简化版扫雷游戏。 如上图所示&#xff0c;游戏包括基本的扫雷功能&#xff1a;生成雷区、左键点击扫雷、右键标记地雷、显示数字提示…

【重新认识C语言----文件管理篇】

目录 ​编辑 -----------------------------------------begin------------------------------------- 引言 1. 文件的基本概念 2. 文件指针 3. 文件的打开与关闭 3.1 打开文件 3.2 关闭文件 4. 文件的读写操作 4.1 读取文件 4.1.1 使用fgetc()读取文件 4.1.2 使用fg…

EasyExcel 导出合并层级单元格

EasyExcel 导出合并层级单元格 一、案例 案例一 1.相同订单号单元格进行合并 合并结果 案例二 1.相同订单号的单元格进行合并2.相同订单号的总数和总金额进行合并 合并结果 案例三 1.相同订单号的单元格进行合并2.相同订单号的商品分类进行合并3.相同订单号的总数和总金额…

WPF 进度条(ProgressBar)示例一

本文讲述&#xff1a;WPF 进度条(ProgressBar)简单的样式修改和使用。 进度显示界面&#xff1a;使用UserControl把ProgressBar和进度值以及要显示的内容全部组装在UserControl界面中&#xff0c;方便其他界面直接进行使用。 <UserControl x:Class"DefProcessBarDemo…

LabVIEW自定义测量参数怎么设置?

以下通过一个温度采集案例&#xff0c;说明在 LabVIEW 中设置自定义测量参数的具体方法&#xff1a; 案例背景 ​ 假设使用 NI USB-6009 数据采集卡 和 热电偶传感器 监测温度&#xff0c;需自定义以下参数&#xff1a; 采样率&#xff1a;1 kHz 输入量程&#xff1a;0~10 V&a…

新能源产业的质量革命:六西格玛培训如何重塑制造竞争力

在新能源行业狂飙突进的今天&#xff0c;企业若想在全球供应链中占据高地&#xff0c;仅靠技术突破已远远不够。制造效率的毫厘之差&#xff0c;可能成为市场话语权的千里之距。某光伏巨头曾因电池片良率低于行业均值1.5%&#xff0c;导致年损失超2.3亿元——这恰恰印证了六西格…

(11)gdb 笔记(4):设置执行方向 set exec-direction,

&#xff08;28&#xff09;引入 record 后&#xff0c;可以 设置执行方向 set exec-direction &#xff1a; 实践&#xff1a; &#xff08;29&#xff09; &#xff08;33&#xff09; 谢谢