我们可以使常规(POJSO)JS对象可迭代,如下所示:
const tempObj = {a: 1, b: 2, c: 3};
tempObj[Symbol.iterator] = function () {
const self = this;
const keys = Object.keys(self);
return {
next() {
const k = keys.shift();
return {
done: !k,
value: [k, self[k]]
}
}
}
};
现在我们可以使用for..of
循环:
for (let [k,v] of tempObj) {
console.log(k,v);
}
我们得到:
a 1
b 2
c 3
我的问题是 - 除了next()之外,我们还需要实现另一种方法吗?如果没有,为什么迭代器规范选择返回一个对象而不是只返回一个函数?为什么不是简单的规范:
tempObj[Symbol.iterator] = function () {
return function next {
return {
done: Object.keys(this).length === 0,
value: Object.keys(this).shift()
}
}
};
我唯一的猜测是,通过返回一个对象,它为更新/更改留下了空间。
答案 0 :(得分:2)
Iterator接口还支持另外两种可选方法:return
和throw
。来自the ES6 specification,第25.1.1.2节(表54):
<强>返回强>
返回IteratorResult对象的函数。归来了 对象必须符合IteratorResult接口。调用此 方法通知Iterator对象调用者不打算 再向Iterator调用下一个方法。归来了 IteratorResult对象通常具有其值的done属性 为true,并且value属性的值作为参数传递 返回方法。但是,此要求未得到强制执行。
<强>抛强>
返回IteratorResult对象的函数。返回的对象 必须符合IteratorResult接口。调用此方法 通知Iterator对象调用者已检测到错误 条件。该参数可用于识别错误条件 并且通常是一个异常对象。典型的回应是 抛出作为参数传递的值。如果方法没有抛出, 返回的IteratorResult对象通常具有done属性 它的价值是真的。
ES6规范还说:
这些方法的调用者通常应在调用它们之前检查它们是否存在。
所以你绝对不需要实施它们;检查他们存在的负担是在来电者身上。
答案 1 :(得分:2)
除
next()
之外还有其他方法需要实现吗?
不,我们需要来实现,但我们可以为完整{{3}实施throw
和return
}} 即可。例如,生成器对象可以做到这一点。
为什么迭代器规范选择返回一个对象而不是只返回一个函数?
因为迭代器(通常)是有状态的,并且从OOP的角度来看,它应该是一个方法而不是(纯)函数。这也允许迭代器实例的原型继承。
答案 2 :(得分:1)
您可以生成Object.entries
作为值的生成器。
let tempObj = { a: 1, b: 2, c: 3 };
tempObj[Symbol.iterator] = function* () {
yield* Object.entries(this);
};
for (let [k, v] of tempObj) {
console.log(k, v);
}