ES6 Iterator

发布时间 2023-11-29 18:09:13作者: 我是小凳子

Iterator (遍历器)

  1. 是一种接口,为各种不同的数据结构提供统一的访问机制。主要供 for...of 消费。

  2. 每调用一次 next() 就会返回数据结构当前成员的信息:{ value: '', done: false/true }

  • value 当前成员的值。done 布尔值,遍历是否结束(即是否有必要再一次调用 next() 方法)。
  1. 一种数据结构只要是部署了 Iterator 接口,这种数据结构就是“可遍历的
  • 默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,即只要用 Symbol.iterator 属性就可以认为是“可遍历的”。

  • Symbol.iterator 属性本身是一个函数。执行 Symbol.iterator 这个属性,会返回一个遍历器对象,该对象的根本特征就是具有 next 方法,每调用一次 next 方法就会返回一个当前成员的信息对象。

  1. 原生具备 Iterator 接口的数据结构有:Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象

对象是没有默认 Iterator 接口的,不能直接用 for...of 遍历。

本质上,遍历器是一种线性处理,对于任何非线性的数据接口,部署遍历器接口就等于部署一种线性转换。

  1. 对于类似数组的对象(存在数值键名和 length 属性),可以将 Symbol.iterator 方法直接引用数组的 Iterator 接口:
const obj = {
  0: "a",
  1: "b",
  2: "c",
  length: 3,
  [Symbol.iterator]: Array.prototype[Symbol.iterator],
};
for (let i of obj) {
  console.log(i);
}
// a
// b
// c

以上代码也可以用另一个简便的方法:使用 Array.from()

了解一下:Array.from() 将一个类似数组或者可迭代对象创建一个新的前拷贝的数组实例。

const obj = {
  0: "a",
  1: "b",
  2: "c",
  length: 3,
};
for (let i of Array.from(obj)) {
  console.log(i);
}

普通对象部署数组的 Symbol.iterator 方法,并无效果。

调用 Iterator 接口的场合

  1. 解构赋值:对数组和 Set 结构进行解构赋值时会默认调用 Symbol.iterator 方法。

  2. 扩展运算符(...)也会默认调用 Iterator 接口。只要是部署了 Iterator 接口的数据结构,就可以使用扩展运算符将其转为数组。

const str = "abc";
console.log([...str]); // [ 'a', 'b', 'c' ]
  1. yield* 后边跟的是一个可遍历的结构,它会调用该结构的 Iterator 接口。

  2. 接受数组作为参数的场合都调用了 Iterator 接口(因为数组的遍历会调用遍历器接口)。

  • for...of
  • Array.from()
  • Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]])
  • Promise.all()
  • Promise.race()

字符串的 Iterator 接口

字符串是一个类似数组的对象,也原生具有 Iterator 接口。

Iterator 接口与 Generator 函数

遍历器对象的 return() , throw()

遍历器对象除了具有 next() 还有 return() 和 throw() , return() 和 throw() 方法是否部署是可选的。

  1. return() 的使用场合:for...of 循环提前退出(通常是:抛出错误或者是 break / return 语句)就会调用 return() 方法。
  • 抛出错误的情况:先执行 return() 方法,再抛出错误。

  • return() 必须返回一个对象,这是 Generator 语法决定的。

  1. throw() 方法主要是配合 Generator 函数使用,一般的遍历器对象用不到这个方法。

for...of

只要是有部署了 Symbol.iterator 属性的,都可以使用 for...of 来遍历其成员。

  1. 使用范围:数组、字符串、Set 和 Map 结构、某些类似数组的对象(如 arguments 对象、DOM NodeList 对象)、Generator 对象。
  • 对于字符串来说, for...of 会正确识别 32 位 UTF-16 字符。
  1. for...of 可以代替数组实例的 forEach() 方法

  2. for...of 与 for...in 的区别:

  • for...in 循环读取键名, for...of 循环读取键值
const arr = ["a", "b", "c"];

// for...in
for (let i in arr) {
  console.log(i);
}

// for...of
for (let i of arr) {
  console.log(i);
}
  • for...of 只返回具有数字索引的属性。
let arr = [3, 5, 7];
arr.foo = "hi";

// for...in
for (let i in arr) {
  console.log(i); // "0", "1", "2", "foo"
}

// for...of
for (let i of arr) {
  console.log(i); // "3", "5", "7"
}
  • for...in 可以用来遍历对象的键名。for...of 不能直接用来遍历对象。

多种遍历语法的比较

  1. for 循环

  2. Array.forEach() 无法中途跳出循环,break 和 return 命令都不奏效。

  3. for...in 遍历键名。主要是为遍历对象而设计的,不适用于遍历数组。缺点有:

  • 数组的键名是数字,但是 for...in 循环是以字符串作为键名“0”、“1”、“2”等等。

  • for...in 循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。

  • 某些情况下,for...in 循环会以任意顺序遍历键名。

  1. for...of 可以与 break、return 配合使用。提供了遍历所有数据结构的统一操作接口。