ES6生成器:可迭代协议与迭代器协议
ES6(ECMAScript 2015)中提出了生成器的概念,进一步完整了JavaScript语言。 本文介绍了可迭代协议与迭代器协议的概念区别,以及生成器的声明与使用方法。
生成器函数
生成器函数是用来返回生成器的函数,生成器是一种有状态的迭代器,
可实现较复杂的迭代行为,比如生成ID。
生成器函数使用function*
语法来定义:
function* idMaker(){
var index = 0;
while(index<3){
yield index++;
}
}
生成器函数也可以通过
GeneratorFunction
(类似Function
)、function* expression
来定义(可以使用匿名函数)。
调用生成器函数并不会执行函数体,而是会返回一个生成器:
var gen = idMaker();
生成器
ES6中生成器有三个方法:
Generator.prototype.next()
: 返回下一个yield
的值。Generator.prototype.return()
: 返回并结束生成器。Generator.prototype.throw()
: 抛出错误。
示例代码:
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
可迭代协议
可迭代协议(iterable protocol)使得我们可以定制JavaScript对象
的迭代行为,比如定义for...of
时迭代出来怎样的值。
将[Symbol.iterator]
属性定义为一个迭代器对象即可实现该协议。
String
, Array
, Map
等内置类型是满足可迭代协议的,例如:
var someString = "hi";
var iterator = someString[Symbol.iterator]();
iterator.next(); // { value: "h", done: false }
iterator.next(); // { value: "i", done: false }
iterator.next(); // { value: undefined, done: true }
迭代器协议
迭代器协议(iterator protocol)又称生成器协议,
该协议定义了什么是迭代器对象。其实迭代器协议很简单,
只要实现.next()
方法(并具有对应语义)即可。
该方法返回的对象除.value
属性外,
还应有一个.done
属性来标识迭代器是否已越过最后一个元素:
function* g(){
yield 1;
yield 2;
}
var iterator = g();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
生成器函数中的return
会立即结束生成器,因此done
会立即变为true
(不同于yield
)。
function* g(){
yield 1;
return 2;
}
var iterator = g();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: true }
console.log(iterator.next()); // { value: undefined, done: true }
yield*
yield*
可以将需要yield
的值委托给另一个生成器,或其他任何可迭代对象
(由ES6 迭代协议规约)。例如:
function* g1() {
yield 2;
yield 3;
yield 4;
}
function* g2() {
yield 1;
yield* g1();
yield 5;
}
var iterator = g2();
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: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
除了生成器外,yield*
还可以委托给其他的可迭代类型:
function* g() {
yield* [1, 2];
yield* "34";
yield* arguments;
}
var iterator = g(5, 6);
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: "4", done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: 6, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
参考阅读
- iteration protocols: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
function*
: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function*- 生成器:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator
- 迭代协议:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols
yield
: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/yieldyield*
: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/yield*
文中代码来自MDN。
本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2016/08/02/es6-generator.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。