迭代数据的方式从使用 for 循环转变到使用迭代器对象,
for 循环需要 初始化变量以便追踪集合内的位置,
而迭代器则以编程方式返回集合中的下一个项。
迭代器 能使操作集合变得更简单。
当新的数组方法与新的集合类型(例如 Set 与 Map ),迭代器就是高效数据处理的关键。
新迭代器:新增的 for-of ,扩展运算符( ... ),能让异步操作更易完成。
1.循环的问题
2.何为迭代器?
3.何为生成器?
循环的问题
var colors = ["red", "green", "blue"];
for (var i = 0, len = colors.length; i < len; i++) {
console.log(colors[i]);
}
这个循环非常直观,然而当它被嵌套使用并要追踪多个变量时,情况就会变得非常复 杂。额外的复杂度会引发错误,而for 循环的样板性也增加了自身出错的可能性,因为相似的代码会被写在多个地方。
迭代器正是用来解决此问题的.
何为迭代器?
迭代器是被设计专用于迭代的对象,带有特定接口。所有的迭代器对象都拥有 next() 方 法,会返回一个结果对象。该结果对象有两个属性:对应下一个值的value ,以及一个布尔 类型的 done ,其值为 true 时表示没有更多值可供使用。迭代器持有一个指向集合位置的内部指针,每当调用了 next() 方法,迭代器就会返回相应的下一个值。
若你在最后一个值返回后再调用 next() ,所返回的 done 属性值会是 true ,并且 value 属性值会是迭代器自身的返回值( return value,即使用 return 语句明确返回的 值)。该“返回值”不是原数据集的一部分,却会成为相关数据的最后一个片段,或在迭代器未 提供返回值的时候使用 undefined 。迭代器自身的返回值类似于函数的返回值,是向调用者 返回信息的最后手段。
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);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 之后的所有调用
console.log(iterator.next());
根据 ES6 制定的规则来书写迭代器,是有一点复杂的。
幸好, ES6 还提供了生成器,让创建迭代器对象变得更简单。
何为生成器?
生成器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 生成器能像正规函数那样被调用,但会返回一个迭代器
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
createIterator() 前面的星号让此函数变成一个生成器。
yield 关键字也是 ES6 新增的, 指定了迭代器在被 next() 方法调用时应当按顺序返回的值。
调用一次next() 然后停止,直到下一次调用next()才会与运行 然后停止.
yield 关键字可以和值或是表达式一起使用.
使用for循环栗子:
function *createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next());
console.log(iterator.next());
生成器函数是 ES6 的一个重要特性,并且因为它就是函数,就能被用于所有可用函数的位置。
yield 关键字只能用在生成器内部,用于其他任意位置都是语法错误,即使在生成器内部的函数中也不行:
function *createIterator(items) {
// 只能在此处使用 yield
items.forEach(function(item) {
// 语法错误
yield item + 1;
});
}
声明 生成器 一定要有*号:
可以使用匿名函数,但不能将箭头函数创建为生成器
let createIterator = function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
};
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next());
生成器就是函数,因此也可以被添加到对象.
ES5:
var o = {
createIterator: function *(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);
使用 ES6 方法的速记法,只要在方法名之前加上一个星号( * ):
var o = {
*createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i];
}
}
};
let iterator = o.createIterator([1, 2, 3]);