This is the 18th day of my participation in the August Challenge
π’ Hi, my name is Xiao Cheng. This article will take you through the iterators in ES6.
Found the problem
Before the iterator pattern was introduced in ES6, what were the problems with traditional iteration? Why add the iterator concept?
Let’s start with a couple of examples
let arr = ['small'.'cheng'.'ah']
Copy the code
This is a simple array, and if we want to get each item of it, we can do a for loop, or we can do a forEach loop, which is cool
The forEach loop was explained in the previous article, linked in the original article
It’s not a problem when it’s pure, right
Let’s look at the following example. Prints the given string as a single character
let str = '011010'
Copy the code
You can use for loops and for… In circulation
And so the problem arose
In both cases, our goal is to traverse, but we need to consider different ways to traverse
In the first code we iterate over an array, in the second we iterate over a string, and we do it differently, which means we tend to iterate differently for different data structures.
In JavaScript, the existing data structures for “collections” are Array and Object. In ES6, Map and Set have been added, and these data structures can also be combined. Faced with so many data structures, we can not use a unified traversal method to obtain the data, this is the problem!
Of course, ES6 provides a new traversal method for… Of loop, but for… “Of” has a very important aspect
“Can only iterate over objects that implement the Iterator interface.”
So for… “Of” is simply iterator’s hired hand, also known as syntax sugar
Knowing the problems existing in the previous traversal method, the protagonist enters the stage, with the problem, for… How does the OF loop achieve uniform traversal? Keep reading
The Iterator Iterator
Iterator is an interface that provides a unified access mechanism for various data structures. Any data structure can be iterated by deploying the Iterator interface.
1. The function of Iterator
-
Provide a unified and easy access interface for various data structures
-
Allows the members of a data structure to be arranged in some order
-
ES6 created a new traversal command for… The of loop is an Iterator interface for… Of consumption.
2. How Iterator works
- Creates a pointer object that points to the start of the current data structure
- First call
next
Method that points to the first member of the data structure - Next call
next
Method that moves the pointer back until it points to the last member
Each call to the next method returns a value, which is an Object containing two properties, value and done. Value indicates the returned value, done is Boolean and indicates whether the collection has been traversed, true if it has, and false otherwise.
3. Implement iterator interface by hand
function myIterator(arr) {
let nextIndex = 0;
return {
next: function () {
return nextIndex < arr.length ? {
value: arr[nextIndex++],
done: false}, {value: undefined.done: true}}}}let arr = [1.2.'ljc']
let it = myIterator(arr)
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Copy the code
MyIterator is an iterator generator that returns an iterator object, which is also a pointer.
We move the pointer through the next method, which internally stores the value of pointer nextIndex through a closure. Each time we call nextIndex, nextIndex will +1, and then fetch data from the array as value according to the value of nextIndex. When no data is available and the maximum index of the array exceeds, no data is returned. In this case, done is true
iterable
Now that we know about Iterator, and we already know how to create an iterator object, this is different from what we said earlier about for… What does the “of” loop matter
First of all we need to know for… Operation mechanism of
When the for… Iterator (); iterator (); iterator (); iterator (); iterator (); iterator (); Of variables, so as to get a specific value, to achieve traversal.
1. Implement iterable objects by hand
A data structure can be considered “traversable” as long as it has the symbol. iterator property.
The symbol. iterator property is itself a function, the default traverser generator for the current data structure, which returns an iterator object.
That is, to implement an iterable, simply deploy the symbol. iterator property on the object and create an iterator method for it
let iteratorObj = {
items: [1.2.'ljc'].// Deploy the symbol.iterator property
[Symbol.iterator]: function () {
let self = this
let i = 0
return {
next: function () {
// Type is converted to Boolean
let done = (i >= self.items.length)
// Data validation
letvalue = ! done ? self.items[i++] :undefined
// Data is returned
return {
done,
value
}
}
}
}
}
for (let item of iteratorObj) {
console.log(item); // 1 2 ljc
}
Copy the code
Obviously implements the Iterator interface, which can be used for… Of Successfully traversal
2. Native application scenarios of Iterator
There are objects for which we do not deploy the Iterator interface, but we can still use for… Of traverses. This is because some objects in ES6 already have this interface deployed by default.
A data structure that has an Iterator interface natively:
- Array
- Set the container
- The map container
- String
- The arguments object for the function
- The NodeList object
Array
Iterator () : iterator (); iterator () : iterator (); iterator () : iterator (); The of loop executes successfully
let arr = [1.2.3]
let it = arr[Symbol.iterator]()// Return an iterator object
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
for (let item of arr) {
console.log(item);
}
Copy the code
The other several are a routine, not to say
Q&A
Looking at this, you might be wondering why so many data structures are deployed by default, but why not objects?
Of course there’s a reason
Objects may have a variety of properties, unlike arrays where the values are ordered, so we don’t know how to determine the order of the object traversal, so we need to manually implement it, right
Early exit cycle
Normal for loops can be broken at any time, for… The of loop is also available as an upgrade to for and forEach
In addition to the next method, iterators also have two alternative methods: return and throw
The return method is used when for… The return method is called when the of loop exits prematurely.
In particular, the return method must have a return value of type Object
We add the return method to the previous code and add the for… In the of loop, a break statement is used to interrupt the loop, the loop exits prematurely, and the return method is automatically called to output the exit prematurely
let iteratorObj = {
items: [1.2.'ljc'].// Deploy the symbol.iterator property
[Symbol.iterator]: function () {
let self = this
let i = 0
return {
next: function () {
// Type is converted to Boolean
let done = (i >= self.items.length)
// Data validation
letvalue = ! done ? self.items[i++] :undefined
// Data is returned
return {
done,
value
}
},
return () {
console.log('Early exit');
return {
done: true
}
}
}
}
}
for (let item of iteratorObj) {
console.log(item); / / 1
break;
}
Copy the code
Pay attention to
If you exit by throwing an exception, the return method is executed before the exception is thrown
Throw methods will be covered in the next generator article
Usage scenarios of the Iterator interface
In addition to the for… In addition to the iterator interface, several scenarios are called automatically by the of loop
1. Deconstruct assignment
When destructuring an iterable, the symbol. iterator method is called by default
let map = new Set().add('a').add('b');
let [x, y] = map
console.log(x, y, map) // a b Set(2)Β {"a", "b"}
Copy the code
Since destructible assignment applies to iterables, let’s try destructing assignment for our own custom iterables
let iteratorObj = {
items: [1.2.'ljc'].// Deploy the symbol.iterator property
[Symbol.iterator]: function () {
let self = this
let i = 0
return {
next: function () {
// Type is converted to Boolean
let done = (i >= self.items.length)
// Data validation
letvalue = ! done ? self.items[i++] :undefined
// Data is returned
return {
done,
value
}
}
}
}
}
let [a, b, c] = iteratorObj
console.log(a, b, c)// 1 2 'ljc'
Copy the code
Successful implementation of deconstruction assignment
2. Extend operators
The extension operator also calls the symbol. iterator method by default, which converts the current data structure to an array
// The example of Teacher Ruan
var str = 'hello';
[...str] // ['h','e','l','l','o']
let arr = ['b'.'c'];
['a'. arr,'d']
// ['a', 'b', 'c', 'd']
Copy the code
3. yield*
Yield * is followed by a traversable structure, which invokes the traverser interface of that structure.
let generator = function* () {
yield 1;
yield* [2.3.4];
yield 5;
}
Copy the code
This is not its main battlefield, as explained in the next section
conclusion
New data structures have been added in ES6. In order to provide a unified approach to traversal, for… Of ways. And the for… The iterator is automatically called when the of is executed
Only objects that implement the Iterator interface can use for… of
An iterator is a method that returns an iterator object
Iterator is used in many scenarios in ES6, and it’s worth noting that new things tend to go up
The next article will cover generators
Thank you very much for reading, welcome to put forward your opinion, if you have any questions, please point out, thank you! π