Iterator 迭代器
定义
迭代器是一个特殊对象,每个迭代器都有一个 next() 方法,每次调用都返回一个结果对象;结果对象有两个属性:一个是 value 表示当前迭代返回的值,另一个是 done 表示迭代是否完成。
ES5 实现
function createIterator(items) {
var i = 0;
return {
next: function () {
var done = i >= items.length;
var value = done ? undefined : items[i++];
return { value, done };
}
};
}
const iterator = createIterator([1, 2, 3]);
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: 3, done: false}
iterator.next(); // {value: undefined, done: true}
Generator 生成器
定义
生成器是返回迭代器的函数
使用
ES6 支持通过 * 与 yield 关键字实现
// 声明
function *createItrator() {
yield 1;
yield 2;
yield 3;
}
// 表达式
const createIterator = function *(){
yield 1;
yield 2;
yield 3;
}
const iterator = createIterator();
iterator.next(); // {value: 1, done: false}
iterator.next(); // {value: 2, done: false}
iterator.next(); // {value: 3, done: false}
iterator.next(); // {value: undefined, done: true}
- yield 通过它来指定调用迭代器的 next() 方法时的返回值及返回顺序。
- 每执行一条 yield 语句之后函数就会停止执行,直到再次调用迭代器的 next() 方法
yield 的使用限制
yield 只可以在生成器的内部使用,否则会会抛出错误,即便是生成器内部的函数里使用也是如此;
function *createIterator(items) {
items.forEach(function() {
yield item + 1; // 在内部函数中使用,导致语法错误
})
}
// Uncaught SyntaxError: Unexpected identifier
yield 与 return 关键字一样,二者都不能穿透函数边界。
生成器对象的方法
ES6 函数方法的简写
let o = {
*createIterator(items) {
items.forEach(function() {
yield item + 1; // 语法错误
})
}
}
可迭代对象和 for-of 循环
可迭代对象具有 Symbol.iterator 属性,Symbol.iterator 通过指定的函数返回一个作用域附属对象的迭代器。
const arr = [1, 2, 3];
for (let num of arr) {
console.log(num);
}
for-of 循环代码通过调用 values 数组的 Symbol.iterator 方法来获取迭代器,随后迭代器的 next() 方法被多次调用,从其对象的 value 属性读取值并存储在变量 num 中
访问默认迭代器
let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
console.log(iterator.next()); // {value: 1, done: false}
判断是否为可迭代对象
function isIterable(object) {
return typeof object[Symbol.iterator] === 'function'
}
创建可迭代对象
默认情况下,开发者定义的对象都是不可迭代对象,但如果给 Symbol.iterator 属性添加一个生成器,则可以将其变为可迭代对象
let collection = {
items: [],
*[Symbol.iterator]() {
for (let item of this.items) {
yield item;
}
}
}
collection.item.push(1);
collection.item.push(2);
collection.item.push(3);
for (let x of collection) {
console.log(x);
}