This is the fifth day of my participation in the August More text Challenge. For details, see:August is more challenging

The Iterator Iterator

Iterator is a new set of syntax in ES6, but there is no Iterator class in ES6. An Iterator is a mechanism (interface) that provides a uniform access mechanism for various data structures. Any data structure can be traversed by deploying an Iterator interface, processing all members of that data structure in turn. Features of iterators:

  • Have the next method to iterate over/iterate over members of the data structure once
  • Done: false, value: XXX}
    • Done Indicates whether the traversal is complete
    • Value: indicates the result of the current traversal
// Simulate the traverser
class Iterator{
	constructor(assemble){
		//assemble: The number is the index level, with length attribute.
		this.assemble = assemble;
		this.index = 0;
	}
	next(){
		if(this.index > this.assemble.length){
			return {done: true.value:undefined};// Indicates that the traversal is complete
		}
		return{
			done: false.value: this.assemble[this.index++]; }}}Copy the code

Although there is no Iterator class in ES6, some data structures already implement Iterator’s iterable specification by default. All data structures (values) that have a Symbol. Iterator attribute are iterable and can be traversed based on a for of loop. Objects do not have a Symbol. Iterator property by default, so objects belong to non-traversable data structures. Common data structures are:

  • An array of
  • Arguments, NodeList, HTMLCllection…
  • String
  • Set
  • Map
  • generator object

For of is internally iterated according to iterator.next, so only data structures that have Symbol

You can use for of to iterate

	let arr = [1.2.3.4];
	for(let item of arr){
		console.log(item);
	}
	// Output 1, 2, 3, 4
Copy the code

Make objects iterable

let obj = {
	0: 10.1: 20.2: 30[Symbol.iterator]:function(){
		let self = this, index = 1;
		return{
			next(){
				if(index > self.length){
					return {done: true.value:undefined};// Indicates that the traversal is complete
				}
				return{
					done: false.value: self[index++];
				}
			}
		}
	}
}
Copy the code

The Generator Generator

A generator object is returned by a generator function, and it conforms to the iterable specification and is iterable. Generator functions are defined by function*, for example function* fn(){}

  • Proto__ === function.prototype
  • Generator function is GeneratorFunction instance, generator function. __ proto__ = = = GeneratorFunction. The prototype; GeneratorFunction.prototype.__ proto__ === Function.prototype
  • The generator function has the IsGenerator property with the value true
  • The this inside the generator function does not point to an instance of the generator, but to the window
  • Generator functions are not allowed to be new, and instances are created when called as normal functions
    • As with normal function calls, the code inside is not executed
    • The code is executed only on subsequent calls to Next, and ends every time next is executed with a yield
    • The result returned each time conforms to the iterator specification
    • {done: true/false, value:yield;}
function* func(){}
let itor = func();// The code inside the function is not executed until a subsequent call to next
({}).toString.call(func);//[object GeneratorFunction]
({}).toString.call(itor);//[object Generator];
Copy the code
function* func(){
	console.log('A');
	yield 1;
	console.log('B');
	yield 2;
	console.log('C');
	yield 3;
	console.log('D');
	yield 4;
}
let itor = func();// Internal code will not be executed
console.log(itor.next());//{done:false, value:1}
console.log(itor.next());//{done:false, value:2}
console.log(itor.next());//{done:false, value:3}
console.log(itor.next());//{done:true, value:4}
Copy the code

The next pass parameter can be passed as the result of the last yield, but the yield is followed by the value after each next

function* func(){
	let x = yield 1;
	console.log(x);
}
let itor = func();
console.log(itor.next(10));// Return value: {done:false, value:1
console.log(itor.next());// Start execution where the last yield ended, i.e. let x = 10(the value passed last next)
/ / the result output undefined {done: true, value: undefined}
Copy the code

If you use yield* to implement a generator within a generator, when you call next, you will not continue until the generator following yield* has iterated over

function* func1(){
	yield 1;
	yield 2;
}

function* func2(){
	yield 3;
	yield* func1();
	yield 4;
}
console.log(itor.next());//{done:false, value: 3}
console.log(itor.next());//{done:false, value: 1}
console.log(itor.next());//{done:false, value: 2}
console.log(itor.next());//{done:false, value: 4}
console.log(itor.next());//{done:true, value: undefined}

Copy the code

So that’s iterators and generators in JavaScript.