[JavaScript] iterators, generators and iteratable objects

Posted by Salkcin on Sat, 12 Feb 2022 02:16:14 +0100

iterator

What is an iterator
The object that implements the next method is the iterator. The next method can have zero or one parameter and return an object. The format of this object is shown in the following example code:

const iter = {
	next() {
		return {done: false, value: 1}
	}
}

Done indicates whether the iteration is completed, and value indicates the value of the iteration. Suppose we create an array iterator, then the case of done: false occurs when the index of the current traversal is greater than or equal to the length of the array. At this time, it indicates the end of the iteration, and the value is undefined.

Using Iterators

console.log(iter.next()); // {done: false, value: 1}
console.log(iter.next()); // .. Ibid
console.log(iter.next());
console.log(iter.next());

Iteratable object

The object that implements the @ @ iterator method is called an iteratable object. In the code, we use symbol Iterator replaces @ @ iterator as the name of the method@@ The iterator method returns an iterator.

const iterable = {
	names: ['jack', 'tom', 'lily'],
	[Symbol.iterator]: function() {
		let idx = 0;
		return {
			next: () => {
				return {
					done: idx >= this.names.length, 
					value: this.names[idx++]
				};
			}
		}
	}
}

// Get iterator
const iterator = iterable[Symbol.iterator]();

console.log(iterator.next());

It should be noted that every time the @ iterator method is called, a new iterator will be returned.

After the same iterator is iterated (that is, when done: true), no matter how many iterations are performed, the state of the iterator will not be changed. Therefore, the iteratable object returns a new iterator each time to avoid that the object cannot be iterated again after one iteration. You can refer to for of ... Only one instance of an iteratable object can be iterated.

generator

The generator is actually a special iterator. Calling the generator function will return an iterator and execute the generated code through the next method of the iterator. Python has similar functions, and it will be familiar to those who have written it.

function* foo() {
	for(let i=0; i<=10; i++) {
		yield i
	}
}

const generator = foo();
generator.next() // 0
// ...            Continue calling 8 times
generator.next() // 10

The method to define the generator is to add a * after the function keyword, that is, the function * function name.

As mentioned earlier, the generator is a special iterator, so if you print the return value of the generator, you will find that the object returned is in iterator format (similar to {done: false, value: xxx}).

function* MyGenerator() {
    yield 'yield What does it mean:Pause the execution of the current function when executing here'
    yield 'The function after pause can be used next Method continues'
    return 'encounter return Then it will really end, done Will become true'
}

const gen = MyGenerator() //After execution, a pointer is returned, which can be used to execute the next method
console.log(gen.next()) // {value: "yield" means: pause the execution of the current function when executing here ", done: false}
console.log(gen.next())// {value: "the function after pause can continue to execute with the next method", done: false}
console.log(gen.next())// {value: "after encountering return, it will really end, and done will become true", done: true}

Return can be used to terminate the execution of the generator. The return value of the function is in Value.

Return value of yield
The return value of yield is the value passed in the next function. Note that the function stops immediately after the yield expression is executed.

function* gen() {
	const n = yield 10;
	console.log('I am here.')
	return n + 10;
}

const g = gen()
g.next();
g.next(10) // I am here. \n 20

const n = yield 10 above. N will be assigned only when next is executed for the second time.

yield iteratable object*
Using yield * can directly produce iteratable objects. The function is similar to traversing iteratable objects, taking out items, and then yield item s

function* gen() {
	for(const name of names) {
		yield name;
	}
}

function* gen1() {
	yield* names;
} 

The above codes of gen and gen1 are equivalent.

Topics: Javascript Front-end