当前位置: 首页 > article >正文

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),更强大。

http://www.kler.cn/a/537045.html

相关文章:

  • STM32的HAL库开发---高级定时器---输出比较模式实验
  • 从零创建 Vue 3 项目
  • 大语言模型极速部署:Ollama 、 One-API、OpenWebUi 完美搭建教程
  • 在 MySQL 8 中配置主从同步(主从复制)是一个常见的需求,用于实现数据的冗余备份、读写分离等。
  • 从java角度对比nodejs、fastapi,同步和异步区别
  • 【deepseek实战】绿色好用,不断网
  • flutter Selector 使用
  • StarSpider 星蛛 爬虫 Java框架 可以实现 lazy爬取 实现 HTML 文件的编译,子标签缓存等操作
  • 前端导出pdf,所见即所得
  • 芯科科技的BG22L和BG24L带来应用优化的超低功耗蓝牙®连接
  • Spring Boot 有哪些优点
  • 【Redis】事务因WATCH的键被修改而失败 事务队列中的操作被自动丢弃 UNWATCH的应用场景
  • 视频编辑质量评价的开源项目 VE-Bench 介绍
  • 使用deepseek快速创作ppt
  • 基于物联网技术的智能寻车引导系统方案:工作原理、核心功能及系统架构
  • 如何设置Jsoup请求头模拟浏览器访问?
  • redis之AOF持久化过程
  • Plugin有什么作用?Plugin是什么?
  • 探索robots.txt:网站管理者的搜索引擎指南
  • yolov11模型在Android设备上运行【踩坑记录】
  • 【面试】Java高频面试题(2023最新版)
  • e2studio开发RA2E1(9)----定时器GPT配置输入捕获
  • 5.2Internet及其作用
  • EasyExcel 导出合并层级单元格
  • 技术选型对比:Redis 与 MySQL、Dubbo 与 Spring Cloud
  • Baumer工业相机堡盟相机的相机传感器芯片清洁指南