迭代器
哪些类型默认可迭代?
- 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]