迭代器
迭代器是被设计专用于迭代的对象,带有特定接口。所有的迭代器对象都拥有next()
方法,会返回一个结果对象。该结果对象有两个属性:对应下一个值的value
,以及一个布尔类型的 done
,其值为true
时表示没有更多值可供使用。
function createIterator(items) {
var i = 0
return {
next: function() {
var done = (i >= items.length)
var value = !done ? items[i++] : undefined
return {
done: done,
value: value
}
}
}
}
var iterator = createIterator([1, 2, 3])
console.log(iterator.next()) // "{ value: 1, done: false }"
console.log(iterator.next()) // "{ value: 2, done: false }"
console.log(iterator.next()) // "{ value: 3, done: false }"
console.log(iterator.next()) // "{ value: undefined, done: true }
生成器
生成器(generator
)是能返回一个迭代器的函数。生成器函数由放在function
关键字之后的一个星号(*
)来表示,并能使用新的 yield
关键字。将星号紧跟在 function
关键字之后,或是在中间留出空格,都是没问题的,正如下例:
// 生成器
function *createIterator() {
yield 1
yield 2
yield 3
}
// 生成器能像正规函数那样被调用,但会返回一个迭代器
let iterator = createIterator()
console.log(iterator.next().value) // 1
console.log(iterator.next().value) // 2
console.log(iterator.next().value) // 3
yield
关键字也是ES6
新增的,指定了迭代器在被 next()
方法调用时应当按顺序返回的值。
生成器函数表达式
你可以使用函数表达式来创建一个生成器,只要在function
关键字与圆括号之间使用一个星号( *
)即可。例如:
function *createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
let iterator = createIterator([1, 2, 3])
console.log(iterator.next()) // "{ value: 1, done: false }"
console.log(iterator.next()) // "{ value: 2, done: false }"
console.log(iterator.next()) // "{ value: 3, done: false }"
console.log(iterator.next()) // "{ value: undefined, done: true }"
// 之后的所有调用
console.log(iterator.next()) // "{ value: undefined, done: true }"
生成器对象方法
由于生成器就是函数,因此也可以被添加到对象中。例如,你可以在ES5
风格的对象字面量中使用函数表达式来创建一个生成器:
var o = {
createIterator: function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
}
let iterator = o.createIterator([1, 2, 3])
你也可以使用ES6
方法的速记法,只要在方法名之前加上一个星号(*
)
var o = {
*createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
};
let iterator = o.createIterator([1, 2, 3])
访问默认迭代器
你可以使用Symbol.iterator
来访问对象上的默认迭代器,就像这样:
let values = [1, 2, 3]
let iterator = values[Symbol.iterator]()
console.log(iterator.next()) // "{ value: 1, done: false }"
console.log(iterator.next()) // "{ value: 2, done: false }"
console.log(iterator.next()) // "{ value: 3, done: false }"
console.log(iterator.next()) // "{ value: undefined, done: true }"
检测对象是否能迭代
既然 Symbol.iterator
指定了默认迭代器,你就可以使用它来检测一个对象是否能进行迭代,正如下例:
function isIterable(object) {
return typeof object[Symbol.iterator] === 'function'
}
console.log(isIterable([1, 2, 3])) // true
console.log(isIterable("Hello")) // true
console.log(isIterable(new Map())) // true
console.log(isIterable(new Set())) // true
console.log(isIterable(new WeakMap())) // false
console.log(isIterable(new WeakSet())) // false
创建可迭代对象
开发者自定义对象默认情况下不是可迭代对象,但你可以创建一个包含生成器的Symbol.iterator
属性,让它们成为可迭代对象。例如:
let collection = {
items: [],
* [Symbol.iterator] () {
for(let item of this.items) {
yield item
}
}
}
collection.items.push(1)
collection.items.push(2)
collection.items.push(3)
for (let x of collection) {
console.log(x)
}
输出:
1
2
3
网友评论