要理解生成器,先理解迭代器。因为生成器就是返回一个迭代器的函数。
ES5实现的迭代器
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 }"
// for all further calls
console.log(iterator.next()); // "{ value: undefined, done: true }"
ES6中的生成器用法:
// generator
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// generators are called like regular functions but return an iterator
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
生成器函数的有趣之处在于,每次yield之后都会停止执行直到下一次next()调用。
yield关键字只能出现在生成器函数中,出现在其他地方就是语法错误。例如,下面的用法是错误的:
function *createIterator(items) {
items.forEach(function(item) {
// syntax error
yield item + 1;
});
}
此处yield在生成器内部的函数中,这也不可以。
不能够使用箭头函数的方式创建生成器函数。
Iterable和for of循环
Iterable与Iterator(迭代器)关系密切。它是一个包含Symbol.iterator属性的对象。
生成器函数创建的所有Iterator都是Iterable,因为生成器默认加了Symbol.iterator属性。
for of在每次循环执行时都会调用Iterable对象的next方法,并将结果对象中的value存储到一个变量中。用法:
let values = [1, 2, 3];
for (let num of values) {
console.log(num);
}
for of循环首先调用values数组的Symbol.iterator方法生成一个迭代器,然后调用iterator.next()方法。
如果对non-iterable对象和null,undefined调用for of循环,会报错。
访问默认的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 }"
判断是否是Iterable对象
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
手动创建Iterable对象
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);
}