Writing in the front

This article mainly discusses the ES6 Iterator, the purpose is to understand its concept, function, and existing applications, and finally learn to put into practice.

Iterator is a pretty big feature in ES6, and it’s the building block on which many other features operate.

Why is Iterator so high up?

Let’s start with a variable

var arr = ['red'.'green'.'blue'];
Copy the code

This is an ordinary array. If I want to get each item of its data, what should I do?

It’s not that easy, just do a for loop, and if you’re feeling low, do a forEach.

Ok, pull the code right away

//forcyclefor(var i=0; i<arr.length; i++){ console.log(arr[i]); } / /forEacth arr.forEach(item=>{ console.log(item); }); / / results slightlyCopy the code

Ok, nothing wrong.

So let’s go ahead and look at the code below. Given a string, what if I want to print every character?

var str='1234567890';
Copy the code

Seriously? It’s ridiculously simple.

You can do it for in, you can do it for loop, you can do it like an array.

Pull the code right away

//for in
for(var s instr){ console.log(str[s]); //s is the attribute name [key]} // convert to arrayfor(var i =0; i<str.length; i++){ console.log(str[i]); } / / or converted to an Array Array. The prototype. Slice. Call (STR);Copy the code

However, for in is not used to fetch data. It iterates through all the enumerable properties of the object, both on itself and on the prototype chain, so this is not safe.

emmm…. That’s all right. Let’s move on.

Take a look at the following code, given a map object, and output each item of its data.

var map = new Map();
map.set('zhang'.'1000w');
map.set('liu'.'200w');
map.set('sun'.'100w');
Copy the code

ForEach is fine.

map.forEach((val,key)=>{
    console.log(val,key);
})
Copy the code

I’ve read so many questions so ridiculously simple that I’m probably going to flip the table and leave. Please wait and read down slowly.

Found the problem

Ok, so in the last few simple problems, all we did was get each of them.

Of course, there’s a lot of ways to do it, there’s a lot of ways to implement it, for loops, forEach, for in.

But have you found a problem, or we look at it from a higher dimension, in fact, these methods are not universal, that is to say, the above sets of data can not use a unified traversal method for data acquisition.

ForEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach

Ok, there’s nothing wrong with that.

But each time you have to transform, encapsulate, and possibly hack prototypes.

Is there a better, universal way to make it more comfortable for developers to use?

The answer is yes, it didn’t come with ES5, it came with ES6.

NB for of

This way of uniformly traversing different data structures is es6’s for of loop.

The for of loop is very similar to the old for loop. It’s just a new syntax.

Quoting ruan da Da’s book in a sentence, I believe that a look will know.

ES6 uses C++, Java, C#, and Python to introduce for… Of circulation. As a unified way to traverse all data structures.

The key is unity, another is direct value, simplify operations, do not need to declare and maintain what variables, data conversion.

“For of” is a “for of” loop.

Why can for of have this capability, can provide a unified way of data acquisition for different data structures.

Is for of really so powerful, and what are the mechanics behind it?

For of isn’t really powerful, it’s just a new ES6 syntax.

Not all objects can use “for of”. Only objects that implement the Iterator interface can use “for of” to iterate over values.

So “for of” is just syntactic sugar, and the real hero is Iterator.

What ? Iterator…..

– Iterator An Iterator

Iterator is an interface designed to provide a unified data access mechanism for different data structures. The Iterator interface is designed primarily for… To make a purchase.

Iterator has been around for years in many backend languages, such as Java, C++, C#, etc.

Since it is an interface, how do we implement the interface? What are the implementation rules?

Since there is no concept of an interface in javascript, we can understand it as a special kind of object-iterator object, and the methods that return this object are called iterator methods.

First it is an object that has a next method that returns a result value each time it is called.

The resulting value 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 or if there is any data available, true if there is no data available, and false otherwise.

In addition, a pointer to the current collection location is maintained internally, and each time the next method is called, the pointer is moved back one position (think of it as an array index).

Look at the code implementation

function getIterator(list) {
    var i = 0;
    return {
        next: function() {
            var done = (i >= list.length);
            var value = !done ? list[i++] : undefined;
            return {
                done: done, value: value }; }}; } var it = getIterator(['a'.'b'.'c']);
console.log(it.next()); // {value: "a".done: false}
console.log(it.next()); // {value: "b".done: false}
console.log(it.next()); // {value: "c".done: false}
console.log(it.next()); // "{ value: undefined, done: true }"
console.log(it.next()); // "{ value: undefined, done: true }"
console.log(it.next()); // "{ value: undefined, done: true }"

Copy the code

The code above is a mock implementation derived from the basic concept of iterators.

  • getIteratorMethod returns an object-an iterable
  • Object has anextMethod,nextMethods hold Pointers internally through closuresiThe value of each callnextmethodsiThe value of all+ 1.
  • Then according to theiRetrieves data from an array asvalue, and then determine by indexdoneThe value of the.
  • wheni=3When the index exceeds the maximum value of the array, no data can be returnedtrue, traversal is complete.

iterable

At this point we have a general idea of Iterator and how to create an Iterator object. But what does he have to do with “for of”?

For of operation mechanism

When for of executes, the engine automatically calls the iterator methods on the object during the loop, executes the iterator object’s next method in turn, and assigns the value returned by Next to the variables in for of to get the specific value.

I think the above sentence contains an important message – “iterator methods on objects”.

Implement iterables

How can an iterator method exist on an object?

ES6 specifies that whenever you deploy the Iterator interface to an object’s properties, in the form of adding a Symbol. Iterator property to the object, which points to an Iterator method, the Iterator returns a special object-iterator object.

The object that deploys this property and implements the iterator method is called an iterable.

At this point, the object is iterable, which means it can be iterated over by for of.

Symbol.iterator, which is an expression that returns the iterator property of the Symbol object, which is a predefined special value of type Symbol.

For example

Normal objects cannot be traversed by “for of”. Eating them directly will cause an error.

var obj = {};

for(var k of obj){
    
}
Copy the code

Obj is not an iterable object.

So let’s make an object iterable, according to the protocol, which is the implementation.

IterableObj deploys the symbol. iterator property on the iterableObj object, and then creates an iterator method for it, using the iterator rules described above.

Var iterableObj = {items:[100,200,300], [symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done, value: value }; }}; }} // Walk through itfor(var item of iterableObj){ console.log(item); / / 100200300}Copy the code

That’s it. The above object is an iterable and can be consumed by for of.

Iterator native application scenarios

Going back to the beginning of iterating strings, arrays, and maps using for of, we didn’t deploy the Iterator interface for them, but we could still use for of.

This is because some objects in ES6 already have this interface deployed by default, so you don’t need to do anything to iterate over values using for of.

Don’t believe it? I don’t want you to say-letter. I want me to say-letter.

Let’s see if we can get their iterators.

An array of

Var arr=[100,200,300]; var iteratorObj= arr[Symbol.iterator](); // Get the iterator method and return the iterator object console.log(iteratorobj.next ()); console.log(iteratorObj.next()); console.log(iteratorObj.next()); console.log(iteratorObj.next());Copy the code

string

The Iterator interface is also deployed by default because the values of the string themselves are ordered and have array-like properties that allow access through indexes.

var str='abc'; var strIteratorObj = str[Symbol.iterator](); // Get the iterator console.log(striteratorobj.next ()); console.log(strIteratorObj.next()); console.log(strIteratorObj.next()); console.log(strIteratorObj.next());Copy the code

Or just look at whether the property is deployed on the prototype.

The arguments array class

Arguments inside the function is an array of classes. It also supports for of because it also deploys the Iterator interface internally.

We all know that objects do not deploy this interface by default, so the arguments attribute is not on the prototype, but on the object itself.

function test(){
    var obj = arguments[Symbol.iterator]();
   console.log( arguments.hasOwnProperty(Symbol.iterator));
   console.log( arguments);
   console.log(obj.next());
}

test(1, 2, 3);Copy the code

In summary, the objects that have Iterator deployed by default include arrays, strings, sets, maps, and array-like objects (like Arguments objects and DOM NodeList objects).

Code verification is a routine, not to say.

Iterator serves another purpose

Is there anything else Iterator can do besides provide a uniform way to access data from different data structures?

That’s data customizability, because we can control the value of the iterator at will.

For example, the array itself is iterable, and we can override its default iterator.

Var arr = [100200300];for(var o of arr){
    console.log(o);
}
Copy the code

The for of array defaults to the following output

After our transformation

Var arr = [100200300]; arr[Symbol.iterator]=function(){

    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.length);
            var value = !done ? self[i++] : undefined;
            return {
                done: done, value: value }; }}; }for(var o of arr){
    console.log(o);
}
Copy the code

Why is the object not deployed by default

Objects can have various properties, unlike arrays where values are ordered.

Therefore, we do not know how to determine the order of their traversal, so we need to manually implement according to the situation.

extension

The for of the interrupt

We all know that a regular for loop can be broken at any time, but what about for of?

The answer is yes, for of is both for and forEach.

In addition to the next method, iterators have two optional return and throw methods.

If the for of loop exits prematurely, the return method is automatically called. Note that the return method must have a value, and the value must be an Object.

Ps: Exits by throwing an exception, which is executed firstreturnMethod throws an exception.

Var iterableObj = {items:[100,200,300], [symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        },
        return(){
            console.log('Early exit');
            return{// An object must be returneddone:true}}}; }}for(var item of iterableObj){
    console.log(item);
    if(item===200){
        break; }}for(var item of iterableObj){
    console.log(item);
    throw new Error();
}
Copy the code

The ps:throw method is not used here. See you in a future article.

More than a for of

Is there any syntax in ES6 other than the Iterator method that automatically calls an object when executing for of?

Deconstruction assignment

The symbol. iterator method is called by default when destructuring an iterable.

// String var STR ='12345';
var [a,b]=str;
console.log(a,b); // 1 2

//map
var map = new Map();
map.set('我'.'front end');
map.set('is'.'technology');
map.set('who'.'quack');
map.set('the writer'.'zz_jesse'); var [d,e]=map; console.log(d,e); / / /"我"."Front end"] ["Yes"."Technology"]...Copy the code

Similarly, if a normal object is deconstructed, an error is reported.

Because ordinary objects are not iterable.

var [d,e]={name:'zhang'};
Copy the code

Destruct assignment from a custom iterable.

var iterableObj = {
    items:['red'.'green'.'blue'],
    [Symbol.iterator]:function(){
    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.items.length);
            var value = !done ? self.items[i++] : undefined;
            return {
                done: done, value: value }; }}; } } var [d,e]=iterableObj; console.log(d,e); / / red and greenCopy the code

The value of the deconstructed assignment is the return value of the iterator object’s next method, in order.

Extended operator

Execution of extended operators (…) It also calls its symbol. iterator method by default, which converts the current iteration object to an array.

// String var STR ='1234'; console.log([...str]); / / / / [1, 2, 3, 4] into array map object var map = new map ([[1, 2], [3, 4]]). Map [...] / [[1, 2], [3, 4] / /setObject varset= new Set ([1, 2, 3]); Set [...] / / [1, 2, 3]Copy the code

Generic objects cannot be converted to arrays.

var obj={name:'zhang'}; [.. obj] / / an errorCopy the code

As a data source

As data sources, such as API methods that accept an array, they call their own iterators by default.

For example, Set, Map, and array. from

Var arr=[100,200,300]; var arr=[100,200,300]; arr[Symbol.iterator]=function(){

    var self=this;
    var i = 0;
    return {
        next: function() {
            var done = (i >= self.length);
            var value = !done ? self[i++] : undefined;
            return {
                done: done,
                value: value+'Front-end technology'// Notice here}; }}; }for(var o of arr){ console.log(o); } // 100 front-end technology lake // 200 front-end technology lake // 300 front-end technology lakeCopy the code

Coverage completed

/ / generatedsetObject varset  = new Set(arr);
Copy the code

// Call the array. from method array. from(arr);Copy the code

Yield * keywords

Yield * is followed by a traversable structure that also calls iterator functions when executed.

let foo = function* () { yield 1; Yield * (2 and 4]; yield 5; };Copy the code

Yield needs to be highlighted, and will be covered in more detail in the next section.

Determines whether an object is iterable

Since the rules for iterables must deploy the symbol. iterator property on the object, we can basically use this genus to determine whether the object is an iterable, and then know whether we can use the for of value.

function isIterable(object) {
    return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable('abcdefg')); // true
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable("Hello")); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // false
Copy the code

conclusion

The emergence of ES6 brings many new data structures, such as Map and Set. Therefore, a unified data acquisition method for for the convenience of data acquisition is added. When for of is executed, the engine automatically calls the iterator of the object to evaluate it.

Not all objects support this approach, but only those that implement the Iterator interface. Such objects are called iterables.

According to the iterable protocol, the iterator protocol can be implemented.

In addition to unified data access, you can also customize the content of the data you get, as long as you need it.

An iterator is a method that returns an iterator object.

An iterable is an object that deploys the Iterator interface and has the correct Iterator methods.

ES6 in many places are used Iterator, usually can pay more attention to observe, think more step.

It’s the end and the beginning

By now we have been able to customize the iterator according to the rules of the iterator, but the implementation process is a bit complicated, after all, we need to maintain the internal pointer, there is a lot of logic processing, inevitably error.

Is there a more elegant way to do it?

Yes, that’s -generator-generator.

let obj = {
  * [Symbol.iterator]() {
    yield 'hello';
    yield 'world'; }};for (letx of obj) { console.log(x); } / /"hello"
// "world"
Copy the code

As you can see, it’s very compact and doesn’t take much code to generate an iterator.

It has more magical powers than just syntactic sugar for generating iterators.

So fun ability is bound to pick a pick, but it is late today, stay up late hurt the body, this time to fix Iterator.

Next time with Generator.

practice

If you find this article useful, try doing the exercises below to improve your understanding, and then leave your answers in the comments.

  1. Write an Iterator object.
  2. Define an iterable.
  3. Tell me about youIteratorUnderstanding, summative output.

reference

Es6.ruanyifeng.com/#docs/itera…

Developer.mozilla.org/zh-CN/docs/…

www.cnblogs.com/xiaohuochai…

One last thing

I am creating a pure technical exchange group for beginners and intermediate front-end developers, with the goal of learning, communicating, thinking and improving their abilities. Because learning alone is not as good as learning together, and only with more communication can we make progress faster.

  • My ideal model is to let one person learn one technology in depth in each period, and then relay it to everyone, which is similar to a sharing class, so that learning efficiency can be improved exponentially.

  • Or you can follow the sequence of questions in the question bank. Each person can think about one question every day and give a summative output, so as to improve his/her skills and expression ability.

  • In this group, you don’t need to worry about your lack of ability or whether the problem is too small to say. You can speak out boldly and let more people analyze it together. It doesn’t matter if you make mistakes.

If you want to join, please pay attention to the public number “front-end technology river’s lake”, reply “into the group”, I pull you into the group.

I recommend you to pay attention to my public number “front-end technology river’s Lake”, get more original selected articles, in addition in my spare time I made an interview question bank website, used to collect the front end questions, the purpose is to save time, improve efficiency, fragments of time brush questions. I recommend you to pay more attention.

In order to find the entrance of the question bank conveniently and not get lost, the entrance is bound to the independent menu of the official account.

Site entrance – big front-end interview brush questions – http://bigerfe.com/


Finally, I hope this article can give you some help. If there are any mistakes in this article, please refer to them in the comments section.

If this article inspires you, please like it and follow it.

See “Front-end Technology”