For… for… for… for… The difference between in and for of, maybe you just as long as it’s two ways of traversing, for… In can iterate over objects, for… Of cannot traverse an object. Apart from these differences, I can’t think of anything else. Today I will give you an inventory of the following, for… In. And for… The pros and cons of the OF loop mechanism, how it works, and its use in projects

For in loops

1. The for in loop iterates over numeric attributes first.

 let obj ={
            name:'wkm'.age:20[Symbol('AA')]:100.0:10.1:20
        }
        for (const key in obj) {
            console.log("key",key);
        }
         Key 0 key 1 Key name Key age */
Copy the code

Unable to iterate over properties of type Symbol

3. Traverses both private and public enumerable properties

 
       Object.prototype.AAA = 200;
        Object.prototype[10] = 300
        let obj ={
            name:'wkm'.age:20[Symbol('AA')]:100.0:10.1:20
        }
        for (const key in obj) {
            console.log("key",key);
        }
        /* key 0 key 1 key name key age key 10 key AAA */
Copy the code

Look at the result above, because it’s iterating over private and public enumerable properties, let’s say you have a class in your project, and that class has methods on it in its prototype so for in iterating over it, it doesn’t have methods on its prototype but it does. Waste of performance

Based on the above problem we can use obj.hasOwnProperty(key) to avoid falling over public attributes

  Object.prototype.AAA = 200;
        Object.prototype[10] = 300
        let obj ={
            name:'wkm'.age:20[Symbol('AA')]:100.0:10.1:20
        }
        for (const key in obj) {
            if(! obj.hasOwnProperty(key))break // Avoid iterating over public attributes
            console.log("key",key);
        }
        /* key 0 key 1 key name key age */
Copy the code

summary

As you can see from the above example, the disadvantage of the for in loop is that it cannot iterate over properties of type Symbol. It will iterate over private and public enumerable properties, especially public and private enumerable properties by default, which will have a high performance cost. So try not to use the for in loop in the project, encapsulate your own method to traverse the object. In addition to traversing objects, for in traverses arrays and strings, but it cannot traverse Set and map structures

A method that encapsulates a loop object

  1. Can be used to check the data type and check whether the object is written, the following tool function package
// Test method encapsulation of data types
(function ({
    var getProto = Object.getPrototypeOf; // Get the prototype object of the real column.
    var class2type = {};
    var toString = class2type.toString;
    var hasOwn = class2type.hasOwnProperty;
    var fnToString = hasOwn.toString;
    var ObjectFunctionString = fnToString.call(Object);

    [
        "Boolean"."Number"."String"."Symbol"."Function"."Array"."Date"."RegExp"."Object"."Error"
    ].forEach(function (name{
        class2type["[object " + name + "]"] = name.toLowerCase();
    });

    function toType(obj{
        if (obj == null) {
            return obj + "";
        }
        return typeof obj === "object" || typeof obj === "function" ?
            class2type[toString.call(obj)] || "object" :
            typeof obj;
    }
    // Check whether the object is stored.
    function isPlainObject(obj{
        var proto,
            Ctor,
            type = toType(obj);
        if(! obj || type ! = ="object") { // If the type detection is not the object directly returns. -+
            return false;
        }
        proto = getProto(obj); // Get the prototype object of the real column object.
        if(! proto) {return true;
        }
        Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
        return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
    }

    window.toType = toType;
    window.isPlainObject = isPlainObject; }) ();Copy the code
  1. Encapsulates its own method for traversing an object
 const eachObject = function eachObject(obj,callback){
            if(! isPlainObject(obj))throw new TypeError('obj must be an plan object');
            // ensure a function
            if(! (typeof callback =="function")) callback = Function.prototype;
            // Get the array of key names for the traversal object, appended with the Symbol attribute
            let keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj)),
            i=0,
            len = keys.length,
            key,
            value,
            result;
            // forEach loop cannot be terminated
            for(; i<len; i++){ key= keys[i]; value = obj[key]; result = callback(key,value)if(result === falsebreak;

            }
            return obj
        }
        / / test
        let obj={a:1.b:2.c:3}
        eachObject(obj,(key,value) = >{
            console.log(key,value)
        })
Copy the code

For of loops

1. Principle of the for 0f loop

The for of loop is based on Iterator and can be used by any data structure that has an Iterator mechanism

1.1 Traverser mechanism

Iterator is an interface mechanism that provides a unified access mechanism for various data structures. Any data structure that has the Iterator interface deployed can be looped with for of

1.2 Characteristics of traverser mechanism

  1. Have the next method to iterate through the data structure members in turn
  2. Each traversal returns an object {done:false, value: XXXX}
  3. Done: records whether the traversal is complete
  4. Value: indicates the result of the current iteration
According to the above handwritten traverser mechanism
 class Iterator {
            constructor(assemble) {
                this.assemble = assemble;
                this.index = 0;
            }
            // There is a next method
            next() {
                let { index, assemble } = this;
                if (index > assemble.length - 1) {
                    // The traversal is complete
                    return {
                        donetrue.valueundefined}}// Iterate over the future completion
                return {
                    donefalse.value: assemble[this.index++]
                }
            }
        }

        let itor = new Iterator([10.20.30]);
        console.log(itor.next())
        console.log(itor.next())
        console.log(itor.next())
        console.log(itor.next())
Copy the code
By modifying the original traverser mechanism to implement the data once every other loop
 let arr = [10.20.30.40.50.60.70]
        arr[Symbol.iterator] = function(){
            let self = this;
            index = -2;
            return {
                next(){
                    if(index>self.length-1) {return {
                            done:true.value:undefined}}return {
                        done:false.value:self[index+=2]}}}}for(let item of arr){
        /* Loop: 1. First get the [symbol. iterator] attribute value function and execute it to an iterator object 2. Iterator.next ()-> {done,value} 3. If done is true, end the loop */
            console.log(item)
        }
Copy the code

2. Object does not have a traversal mechanism, want it to use for of loop, add traversal to its prototype

 Object.prototype[Symbol.iterator] = function ({
            let obj = this.// Get the key name of the object.
                keys = Object.getOwnPropertyNames(obj).concat(Object.getOwnPropertySymbols(obj))
            index = 0;
            return {
                next() {
                    if (index > keys.length - 1) {
                        return {
                            donetrue.valueundefined}}return {
                        donefalse.value: obj[keys[index++]]
                    }
                }
            }
        }

        let obj = { a1.b2.c3 }

        for (let value of obj) {
            console.log(value)
        }
Copy the code

3 for of summary

  • Data structures with symbol. iterator properties (all can be traversed)
  • For of can iterate over arrays, partial arrays, String Set Map
  • Objects don’t have a traversal mechanism by default, so you can’t use a for of traversal. To use a for of traversal, you must append a traversal to the object prototype

conclusion

For in and for of are both used for traversal. For in can traverse object strings and arrays. However, because for iterates traversable properties on the prototype, its performance is poor, so the method of iterating objects in the project should be encapsulated by itself

Iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator: iterator