为什么我们需要它们以及如何使用它们以及将Iterable功能添加到没有它的对象。这看起来像是一般只是略读的主题。
答案 0 :(得分:2)
我无法相信这里尚未得到解答,但我找不到。
JavaScript迭代器使用全局符号Symbol.iterator
来定义调用时返回对象的函数。该对象有一个方法next
,它返回另一个具有两个属性的对象:value
(迭代器的当前值)和done
(无论迭代器是否完成)。例如:
const foo = {};
foo[Symbol.iterator] = function* () {
let i = 0;
yield ++i;
};
let iter = foo[Symbol.iterator]();
iter.next(); // { value: 1, done: false }
iter.next(); // { value: 2, done: false }
迭代器也可以与for..of
之类的自动构造一起使用。我上面定义的那个不会与for..of
一起使用,因为它永远不会完成:遍历所有它的属性最终会导致内存不足。所以让我们使用一个数组:
const bar = [1,2];
for (let baz of bar) console.log(baz); // logs 1, 2, stops
所有内置集合(弱集合除外)都可以在实现此接口时以这种方式迭代。
如果调用者在用尽之前完成调用,则可以显式关闭保留在文件句柄等资源上的Iterables。例如,我们将使用带有readFromFile
和getNextLine
函数的假设文件API:
const fileReader = {
[Symbol.iterator] (path) {
return {
fileHandle: readFromFile(path),
next () {
return {
value: this.fileHandle.getNextLine(),
done: false
}
}
return () {
this.fileHandle.close();
}
}
}
};
您可以调用return
方法以防止泄漏文件句柄。有关详情,请参阅Reg Braithwaite的this post。
如果您的迭代器是生成器函数,就像我上面的无数计数数列表一样,您可以通过yield
关键字pass it values:
foo[Symbol.iterator] = function* () {
let i = 0;
let reset = yield ++i;
if (reset) i = 0;
};
iter = foo[Symbol.iterator]();
iter.next().value; // 1
iter.next().value // 2
iter.next(true).value // 1 again
所以,让我们说你有一些对象myObject
,你希望能够迭代它们的属性。我们将在下一个示例中忽略Object.entries
:
const myObject = {
a: 1,
b: 2
};
Object.defineProperty(myObject, Symbol.iterator, {
value: function* () {
for (let key in myObject) {
if (myObject.hasOwnProperty(key)) {
yield [key, myObject[key]];
}
}
}
});
iter = myObject[Symbol.iterator]();
iter.next(); // { value: ['a', 1], done: false }
iter.next(); // { value: ['b', 2], done: false }
iter.next(); // { value: undefined, done: true }
在ES 2015之前,对象属性无法保证有订单。如果你在最新的Chrome / FF / Safari中运行它,上面的代码都可以正常运行,但是如果你为旧版浏览器进行操作,你可能会首先看到['b', 2]
输出,或者每次迭代都会改变它。
现在你可能比你真正想要的更多地了解JavaScript迭代。