用循环语句迭代数据时,必须要初始化一个变量来记录每一次迭代在数据集合中的位置,而在许多编程语言中,已经开始通过程序化的方式用迭代器对象返回迭代过程中集合的每一个元素。
迭代器的使用可以极大地简化数据操作,于是ES6也向JS中添加了这个迭代器特性。新的数组方法和新的集合类型(如Set集合与Map集合)都依赖迭代器的实现,这个新特性对于高效的数据处理而言是不可或缺的,在语言的其他特性中也都有迭代器的身影:新的for-of循环、展开运算符(...),甚至连异步编程都可以使用迭代器。
什么是迭代器
迭代器是一种 特殊对象 ,它具有一些专门为迭代过程设计的专用接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done,它是一个布尔型的值,当没有更多返回数据时返回true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值。
什么是生成器
生成器是一种返回 迭代器 的 函数,通过function关键字后星号(*)来表示,函数中会用到新的关键字yield。
手写一个迭代器:
// es5的写法模拟一个迭代器
function creatIterator (items){
var i = 0;
return {
next:function () {
var done = (i>=items.length);
var value = !done ? items[i++] : undefined;
return {
value:value,
done:done
};
}
};
}
var iterator = creatIterator([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}
在上面代码中,creatIterator()方法返回的对象有一个next()方法,每次调用时,items数组的下一个会作为value返回,当i为3时,done变为true,此时value为undefined。done与value二者最后的结果符合es6迭代器的最终返回机制,当数据集被用尽后会返回最终的内容。
上面的示例还是有点复杂,但是ES6引入了一个生成器对象,它可以让创建迭代器对象的过程变得简单很多。看下面的示例:
// 生成器
function *creatIterator (){
yield 1;
yield 2;
yield 3;
}
var iterator = creatIterator();
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}
上述示例中,creatIterator()前的型号表面它是一个生成器,通过yield关键字来指定调用迭代器的next()方法时的返回值和返回顺序。
生成器最有趣的部分是,每当执行完一条yield语句后函数就会自动停止执行。拿上面的例子来说,执行完语句yield 1之后,函数便不再执行其他任何语言,直到再次调用迭代器的next()方法才会继续执行 yield 2 语句。
yield关键字
yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出语法错误,即便是在生成器内部的函数里使用也是如此:
function *creatIterator (items){
items.forEach(function(item){
// 语法错误
yield item + 1;
})
}
从上面的示例看,yield关键字确实在creatIterator()函数内部,但是它与return关键字一样,二者都不能穿透函数边界。嵌套函数中的return语句不能用作外部函数的返回语句,而此处嵌套函数中的yield语句会导致程序抛出语法错误。