跳到主要内容

迭代器和生成器

迭代器

迭代器基础

常见迭代器类型
  • Strings;
  • Arrays;
  • Maps;
  • Sets;
  • The arguments object;
  • DOM collection types;
常见迭代操作
let arr = ["foo", "bar", "baz"];

// for...of loops
for (let el of arr) {
console.log(el);
}
// Array destructuring
let [a, b, c] = arr;
console.log(a, b, c); // foo, bar, baz
// Spread operator
let arr2 = [...arr];
console.log(arr2); // ['foo', 'bar', 'baz']
// Array.from()
let arr3 = Array.from(arr);
console.log(arr3); // ['foo', 'bar', 'baz']
// Set constructor
let set = new Set(arr);
console.log(set); // Set(3) {'foo', 'bar', 'baz'}
// Map constructor
let pairs = arr.map((x, i) => [x, i]);
console.log(pairs); // [['foo', 0], ['bar', 1], ['baz', 2]]
let map = new Map(pairs);
console.log(map); // Map(3) { 'foo'=>0, 'bar'=>1, 'baz'=>2 }

常用 API

迭代
let arr = ["foo", "bar"];
// 访问迭代器
let iter = arr[Symbol.iterator]();
// 迭代器默认为空
console.log(iter); // ArrayIterator {}
// 返回 iterator 的下一个元素 {done, value}
// done 表示是否到达终点, value 对应值
console.log(iter.next()); // { done: false, value: 'foo' }
console.log(iter.next()); // { done: false, value: 'bar' }
console.log(iter.next()); // { done: true, value: undefined }

迭代器进阶

自定义迭代器

  • 使用 Symbol.iterator 属性实现迭代器;
  • 必须实现 next 方法;
  • 返回包括 value 和 done 两属性的对象;
    • value:当前值;
    • done:是否迭代完成;
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1,
limit = this.limit;
return {
next() {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true, value: undefined };
}
},
};
}
}
let counter = new Counter(3);
for (let i of counter) {
console.log(i);
}
// 1
// 2
// 3
关闭迭代器
  • 定义 return 方法手动关闭迭代器;
  • for。。.of 中使用 continue,break,return,throw 会触发 return();
class Counter {
constructor(limit) {
this.limit = limit;
}
[Symbol.iterator]() {
let count = 1,
limit = this.limit;
return {
next() {
if (count <= limit) {
return { done: false, value: count++ };
} else {
return { done: true };
}
},
return() {
console.log("Exiting early");
return { done: true };
},
};
}
}

let counter1 = new Counter(5);
for (let i of counter1) {
if (i > 2) {
break;
}
console.log(i);
}
// 1
// 2
// Exiting early
未 return() 方法
  • 可以继续从上次离开的地方继续迭代;
let a = [1, 2, 3, 4, 5];
let iter = a[Symbol.iterator]();
for (let i of iter) {
console.log(i);
if (i > 2) {
break;
}
}
// 1
// 2
// 3
for (let i of iter) {
console.log(i);
}
// 4
// 5
如何检测 iterator 是否可以停止
  • 检测 iterator 是否具有 return 属性且是否为函数对象