JavaScript 迭代器与生成器

JavaScript 迭代器与生成器

迭代器

迭代器是一种检查容器内元素并遍历元素的数据类型。

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。

生成器

生成器( generator )是能返回一个迭代器的函数。 生成器函数由放在 function 关键字之 后的一个星号( * )来表示,并能使用新的 yield 关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
在循环内遇到yield就会停止,指定再次调用next方法,将会在上次停止的位置继续执行
*/

function* createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
let iterator = createIterator([1, 2, 3])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 之后的所有调用
console.log(iterator.next())
// "{ value: 1, done: false }"
// "{ value: 2, done: false }"
// "{ value: 3, done: false }"
// "{ value: undefined, done: true }"
// "{ value: undefined, done: true }"

关于生成器的几点注意事项:

  • 使用函数表达式来创建一个生成器,只要在 function 关键字与圆括号之间使用一个星号( * )

  • 由于生成器就是函数,因此也可以被添加到对象中,下列两种方法是等价的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var o = {
createIterator: function*(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
}

var o = {
*createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
}

let iterator = o.createIterator([1, 2, 3])
  • 不能将箭头函数创建为生成器

可迭代对象与 for-of 循环

与迭代器紧密相关的是,可迭代对象( iterable )是包含 Symbol.iterator 属性的对象。这 个 Symbol.iterator 知名符号定义了为指定对象返回迭代器的函数。

1
2
3
4
5
let values = [1, 2, 3, {}, null, undefined]

for (const value of values) {
console.log(value)
}

访问默认迭代器

你可以使用 Symbol.iterator 来访问对象上的默认迭代器,就像这样:

1
2
3
4
5
6
7
8
9
10
let values = [1, 2, 3]
let iterator = values[Symbol.iterator]()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// "{ value: 1, done: false }"
// "{ value: 2, done: false }"
// "{ value: 3, done: false }"
// "{ value: undefined, done: true }"

检查一个对象是否能够进行迭代

1
2
3
4
5
6
7
8
9
function isIterable(object) {
return typeof object[Symbol.iterator] === "function"
}
console.log(isIterable([1, 2, 3]))
console.log(isIterable("Hello"))
console.log(isIterable(new Map()))
console.log(isIterable(new Set()))
console.log(isIterable(new WeakMap())) // false
console.log(isIterable(new WeakSet())) // false