问题
I have been trying to make an iterator using a plain function, without a generator or using the Symbol.iterator
protocol for academic purposes. For that, I have made a function that returns an object with a next
parameter, but trying to run it as the iterable
argument of an for...of
loop yields unwanted results.
Here is my code so far, which I copied from the Iterators and Generators page on MDN:
function iterateThis(arr){
let i = 0;
return {
next: function() {
return i < arr.length ?
{value: arr[i++], done: false} :
{done: true};
}
};
}
If I try to run it like so:
const iterable = iterateThis([1,2,3,4,5]);
for(item in iterable){
console.log(item);
}
On the console, I just get a single result: next
.
Am I doing something wrong in the creation of the function iterateThis
? Or is for...of
only designed to work with generators and the Symbol.iterator
property?
Executed on Node v8.11.1
回答1:
The problem is that your iterateThis
function returns an iterator but the for/of
construct expects a iterable.
Okay, wait, whats the difference?
From MDN's page on iteration protocols:
In order to be iterable, an object must implement the
@@iterator
method, meaning that the object (or one of the objects up its prototype chain) must have a property with a@@iterator
key which is available via constantSymbol.iterator
:
On the other hand:
An object is an iterator when it implements a
next()
method with the following semantics: Ommited due to length, TL;DR: The next method returns an object of the form:{value: T, done: boolean}
They are related in that calling the @@iterator
method of an iterable returns an iterator.
The for/of
loop always expects an iterable, so if you want to use for/of
, you have to use @@iterator
/Symbol.iterator
. There's just no way around it as far as I know. But your snippet can be easily modified to use it by just creating an object that returns your iterator when it's Symbol.iterator
method is called:
function iterateThis(arr){
let i = 0;
return {
next: function() {
return i < arr.length ?
{value: arr[i++], done: false} :
{done: true};
}
};
}
function makeIterableFromIterator(iterator) {
return {
[Symbol.iterator]: function() {
return iterator;
}
}
}
const iterator = iterateThis([1, 2, 3, 4, 5]);
const iterable = makeIterableFromIterator(iterator);
for (item of iterable) {
console.log(item);
}
来源:https://stackoverflow.com/questions/50917742/can-i-make-an-iterator-with-a-simple-function-no-generator-or-symbol-iterator