跳到主要内容

迭代器

哪些类型默认可迭代?​

  • String;
  • Array;
  • TypedArray;
  • Map;
  • Set;
  • 函数的 arguments 对象;
  • 部分 DOM 集合类型;

迭代器协议是什么?​

  • 入口: obj[Symbol.iterator]() 返回一个迭代器对象;
  • 迭代器对象: 必须提供 next() 方法;
  • next() 返回值: { done, value }, done 表示是否结束, value 为当前值;
const arr = ["foo", "bar"];
const iter = arr[Symbol.iterator]();
iter.next(); // { done: false, value: 'foo' }
iter.next(); // { done: false, value: 'bar' }
iter.next(); // { done: true, value: undefined }

哪些语法依赖迭代器?​

const arr = ["foo", "bar", "baz"];

for (const el of arr) console.log(el); // for...of
const [a, b, c] = arr; // 解构
const arr2 = [...arr]; // 扩展运算符
const arr3 = Array.from(arr); // Array.from
const set = new Set(arr); // Set 构造
const map = new Map(arr.map((x, i) => [x, i])); // Map 构造
  • 统一入口: 只要实现了 Symbol.iterator, 上述语法都可用;

如何自定义迭代器?​

  • 要求: 在对象上实现 [Symbol.iterator], 返回带 next() 的对象;
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1;
const limit = this.limit;
return {
next() {
return count <= limit ? { done: false, value: count++ } : { done: true, value: undefined };
},
};
}
}
[...new Counter(3)]; // [1, 2, 3]

迭代器如何提前关闭?​

  • return(): 迭代器可提供该方法, 用于提前结束;
  • 触发时机: for...of 中出现 break、return、throw 或 continue 跳出时;
class Counter {
[Symbol.iterator]() {
let count = 1;
return {
next: () => ({ done: false, value: count++ }),
return() {
console.log("Exiting early");
return { done: true };
},
};
}
}
for (const i of new Counter()) {
if (i > 2) break; // 输出 "Exiting early"
}
  • 检测能力: 判断 iterator.return 是否存在且为函数;

没有 return 的迭代器能继续使用吗?​

  • 可以: 未提供 return() 时, 提前跳出后可继续从上次离开的位置迭代;
const a = [1, 2, 3, 4, 5];
const iter = a[Symbol.iterator]();
for (const i of iter) {
if (i > 2) break;
}
[...iter]; // [4, 5]