第八章 迭代器与生成器
迭代器
迭代器是一个特殊对象,每一个迭代器对象有 next()方法,返回一个包含 value 和 done 属性的对象。
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 }"
// 之后的所有调用
console.log(iterator.next()); // "{ value: undefined, done: true }"
生成器
生成器是函数,用于返回迭代器,ES6 内部实现了迭代器功能,只需用 yield 来迭代输出。
function* createIterator() {
yield 1
yield 2
yield 3
}
const a = createIterator()
console.log(a.next()) //{value: 1, done: false}
console.log(a.next()) //{value: 2, done: false}
console.log(a.next()) //{value: 3, done: false}
console.log(a.next()) //{value: undefined, done: true}
在 for 循环中使用 yield 关键字,可以暂停循环,但只能在生成函数内部(内部嵌套函数也不行)使用。
可以用函数表达式表示:
const createIterator = function* () {
yield 1
yield 2
}
也可以在对象内添加:
const obj = {
a: 'hahaha',
*createIterator() {
yield this.a
},
}
let b = obj.createIterator()
console.log(b.next()) // {value: "hahaha", done: false}
可迭代对象与 for-of 循环
可迭代对象指包含了Symbol.iterator
属性的对象。在 ES6 中所有的集合(数组,Set,Map)以及字符串都是可迭代对象。
for-of 循环每次循环都会调用可迭代对象的next()
方法,直至done=true
,循环时将 value 属性值读出并放入 num 变量。
let values = [1, 2, 3];
for (let num of values) {
console.log(num); // 1 2 3 三行显示
}
访问默认迭代器
let iterator = values[Symbol.iterator]();
console.log(iterator.next());
创建可迭代对象
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);
}
内置的迭代器
集合迭代器
数组,Map,Set 有entries()
,values()
,keys()
迭代器
entries() 返回键和值(Map 默认迭代器) values()返回值(数组和 Set 默认迭代器) keys()返回键
for (let entry of map.values()) { // let entry of map 使用默认迭代器
console.log(entry);
}
字符串迭代器
可以正确输出 unicode 字符,使用 for 会返回两个码元(无法识别)。
var message = "A 𠮷 B";
for (let c of message) {
console.log(c);
}
NodeList 的迭代器
var divs = document.getElementsByTagName("div");
for (let div of divs) {
console.log(div.id);
}
扩展运算符与非数组的可迭代对象
可迭代对象转换为数组的最简单方法。
let smallNumbers = [1, 2, 3],
bigNumbers = [100, 101, 102],
allNumbers = [0, ...smallNumbers, ...bigNumbers];
console.log(allNumbers.length); // 7
console.log(allNumbers); // [0, 1, 2, 3, 100, 101, 102]
迭代器高级功能
传递参数给迭代器
传递给next()
的参数会成为上次生成器执行处yield 语句的值,因此第一次执行next()
方法传入任何参数都是无效的。
function* create() {
let first = yield 'hahah'
let second = yield first + 2
}
const b = create()
console.log(b.next(88)) // {value: "hahah", done: false}
console.log(b.next(56)) // {value: 58, done: false}
console.log(b.next()) // {value: undefined, done: true}
在迭代器中抛出错误
function* create() {
let first = yield 'hahah'
let second
try {
yield first + 2
} catch (ex) {
second = 'xixixi'
}
yield second + 'LOL'
}
const b = create()
console.log(b.next(88)) // {value: "hahah", done: false}
console.log(b.next(56)) // {value: 58, done: false}
console.log(b.throw(new Error('yOOO'))) //{value: "xixixiLOL", done: true}
生成器的 Return 语句
使用return
表示处理已完成,done
会设置成true
,如果提供了返回值,则被用于value
。
生成器委托
将多个迭代器的值合并一起使用。
function *createNumberIterator() {
yield 1;
return 2;
}
function *createRepeatingIterator(count) {
for (let i=0; i < count; i++) {
yield "repeat";
}
}
function *createCombinedIterator() {
let result = yield *createNumberIterator();
yield *createRepeatingIterator(result);
}
var iterator = createCombinedIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"