Generator 函数初探
Posted on June 21, 2016
前言
Generator 函数是 ES6 一个很重要的特性,但其涉及的概念却不太能一眼就看懂,所以写下这篇小文以作学习记录。
定义一个 generator 函数
定义一个 generator 函数十分简单,和正常的函数定义相比,多加一个 *
就可以了:
function * name(arguments) {
statements
}
但 generator 函数与普通函数的区别却非常大,它的优势在于,退出函数之后可以再次进入,函数的上下文会被保留。每次退出 generator 函数,它都会返回一个值,这不是一个普通的值,而是一个迭代器(iterator)对象。下面就来说一说迭代器对象。
迭代器对象
迭代器有一个特别棒的特性,就是可以记录当前数组遍历到的节点位置。除此之外,按照 协议规范,迭代器对象需要提供一个 next
方法继续遍历下一个属性值,该方法返回一个如下对象:
{
done: <boolean>, // 用于判断是否已经到数组最尾部
value: <any> // 当前位置的返回值
}
下面让我们实现一个简单的迭代器构造函数:
function Iterator(array){
var position = 0;
return {
next: function () {
if(position < array.length){
return {
done: false,
value: array[position++]
}
}else {
return {
done: true
};
}
}
}
}
var iterableArray = new Iterator([1,2,3]);
console.log(iterableArray.next().value) // 1
console.log(iterableArray.next().value) // 2
console.log(iterableArray.next().value) // 3
console.log(iterableArray.next().done) // true
一些内置的可迭代的对象有 String
、Array
、TypedArray
、Map
、Set
,简单的判断规则就是:可以使用 for...of
遍历的对象。这样的对象也可以使用 扩展运算符(…)、 解构赋值(destructuring assignment) 和 generator,generator 提供了更好的遍历可迭代对象的方法。
yield 关键字
现在我们知道了如何定义 generator 函数以及 generator 函数返回的是迭代器对象。那么就先来试着写一下,注意使用 node --harmony
执行:
function* gen() {
return 'hello';
}
console.log(gen()); // {} - 返回一个迭代器对象
console.log(gen().next()); // { value: 'hello', done: true }
结果符合理论的,接下来我们来解决一个问题:如何在 generator 函数中多次返回 iterator 对象?
为了解决这个问题,ES6 引入了一个关键字 —— yield
,其用处是暂停和继续 generator 函数,并返回一个迭代器对象。再来试一把:
function* gen(name) {
yield 'Hello, ' + name;
return 'Bye, ' + name;
}
console.log(gen('Alice').next()); // { value: 'Hello, Alice', done: false }
console.log(gen('Bob').next()); // { value: 'Hello, Bob', done: false }
References