So many loops in js, for for… in for… Of forEach, some of these loops feel very much the same and today we’re going to talk about the difference between a for loop and a forEach. Let’s discuss it from several dimensions:

  1. forCirculation andforEachThe essential difference between.
  2. forCirculation andforEachGrammatical differences.
  3. forCirculation andforEachPerformance differences.

The essential difference

The for loop is a loop method that has been around since JS was invented. ForEach is an ES5 method for mounting iterable prototypes, such as Array Set Map. ForEach is an iterator that iterates through the iterable. So what are traversal, iteration, and iterable. Traversal: Refers to the behavior of regularly accessing each member of a data structure. Iteration: Iteration is a special form of recursion, a method provided by iterators that, by default, accesses the members of a data structure one by one in a certain order. Iteration is also a traversal behavior. Iterable: Iterable: Array Set Map String arguments NodeList: [Symbol. Iterator] : [Symbol. Iterator] Objects that contain them are considered iterable.

ForEach is an iterator. The essential difference between forEach and a for loop is that forEach iterates through an Array Set Map, whereas a for loop is a loop that iterates through an Array. To talk more about what an Iterator is, remember that Generator, when called, generates an Iterator Object that has a.next() method, Each call returns an object {value:value,done:Boolean}. Value returns the yield value. When yield ends,done becomes true. An iterator is a special kind of object. It is marked in the ES6 specification by the next() method that returns an object, and the iteration behavior is judged in done. Iterators perform traversal without exposing the internal representation. Look at the code

let arr = [1.2.3.4]  // Iterable
let iterator = arr[Symbol.iterator]()  // A call to symbol. iterator yields an iterator object
console.log(iterator.next()); // {value: 1, done: false} accesses the next method of the iterator object
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 4, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
Copy the code

We saw it. As long as it is can be iterative object, call the internal Symbol. The iterator will provide an iterator, and according to the iterator returned the next way to access to the internal, and this is for… Implementation principle of OF.

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

Calling next returns the value of the object and stores it in item until value is undefined and out of the loop, all iterables are available for… Of consumption. Let’s look at the other iterables:

function num(params) {
    console.log(arguments); // Arguments(6) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    let iterator = arguments[Symbol.iterator]()
    console.log(iterator.next()); // {value: 1, done: false}
    console.log(iterator.next()); // {value: 2, done: false}
    console.log(iterator.next()); // {value: 3, done: false}
    console.log(iterator.next()); // {value: 4, done: false}
    console.log(iterator.next()); // {value: undefined, done: true}
}
num(1.2.3.4)

let set = new Set('1234')
set.forEach(item= > {
    console.log(item); // 1, 2, 3, 4
})
let iterator = set[Symbol.iterator]()
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 4, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
Copy the code

Iterators are generated when the Symbol. Iterator property of an iterable is called. ForEach generates an iterator, passing the value of each element in its internal callback function. ForEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach = forEach But using it on a Set Map gives an error, so I assume it’s the iterator called, calling next over and over, passing arguments to the callback function. Since I didn’t find the answer online, I don’t know what to say. If you have an answer, please leave me a message in the comment section.)

forCirculation andforEachGrammatical differences between

Knowing the essential differences, what grammatical differences do they have in the application process?

  1. forEachThe parameters.
  2. forEachInterrupts.
  3. forEachIndex cannot be reset when its element is deleted.
  4. forA loop can control the start of a loop.

forEachThe parameters of the

Do we really know the full content of forEach’s feed? It looks something like this:

arr.forEach((self,index,arr) = >{},this)
Copy the code

Self: The element currently traversed by the array. By default, the array elements are fetched from left to right. Index: The index of the current element in the array. The first element is 0, and so on. Arr: array currently traversed. This: This points to in the callback function.

let arr = [1.2.3.4];
let person = {
    name: 'Tech Straight Star'
};
arr.forEach(function (self, index, arr) {
    console.log(The current element is${self}The index for${index}, belongs to an array${arr}`);
    console.log(this.name+='nice');
}, person)
Copy the code

We can use ARR to implement array de-duplication:

let arr1 = [1.2.1.3.1];
let arr2 = [];
arr1.forEach(function (self, index, arr) {
    arr.indexOf(self) === index ? arr2.push(self) : null;
});
console.log(arr2);   / / [1, 2, 3]

Copy the code

forEachThe interrupt

In javascript, a break return continue is used to interrupt a function or break out of the loop. We use some interrupt behavior in the for loop, which is good for optimizing array traversal search. However, because forEach is an iterator, it can only be traversed in order, so the above interrupt behavior is not supported.

let arr = [1.2.3.4],
    i = 0,
    length = arr.length;
for (; i < length; i++) {
    console.log(arr[i]); / / 1, 2
    if (arr[i] === 2) {
        break;
    };
};

arr.forEach((self,index) = > {
    console.log(self);
    if (self === 2) {
        break; / / an error
    };
});

arr.forEach((self,index) = > {
    console.log(self);
    if (self === 2) {
        continue; / / an error
    };
});
Copy the code

What if I had to break out of the loop in forEach? Try /catch:

try {
    var arr = [1.2.3.4];
    arr.forEach(function (item, index) {
        // Jump conditions
        if (item === 3) {
            throw new Error("LoopTerminates");
        }
        //do something
        console.log(item);
    });
} catch (e) {
    if(e.message ! = ="LoopTerminates") throw e;
};
Copy the code

If a return is encountered, no error is reported, but it does not take effect

let arr = [1.2.3.4];

function find(array, num) {
    array.forEach((self, index) = > {
        if (self === num) {
            return index;
        };
    });
};
let index = find(arr, 2);// undefined
Copy the code

forEachIndex cannot be reset when its element is deleted

In forEach we have no control over the index value, it just increments mindlessly until the length greater than the array jumps out of the loop. Therefore, it is not possible to delete itself to reset index.

let arr = [1.2.3.4]
arr.forEach((item, index) = > {
    console.log(item); // 1, 2, 3, 4
    index++;
});
Copy the code

Index does not change as it is added or subtracted from the function body. In real development, it is quite common to iterate through a number group and delete an item simultaneously, so be careful when using forEach for deletion.

forA loop can control the start of a loop

As mentioned above, the starting point of forEach cycle can only be 0 without human intervention, while for cycle is different:

let arr = [1.2.3.4],
    i = 1,
    length = arr.length;

for (; i < length; i++) {
    console.log(arr[i]) / / 2, 3, 4
};
Copy the code

The previous array traversal and delete spawning operation can be written as

let arr = [1.2.1],
    i = 0,
    length = arr.length;

for (; i < length; i++) {
    // Delete all 1's in the array
    if (arr[i] === 1) {
        arr.splice(i, 1);
        // reset I, otherwise I jumps one bit
        i--;
    };
};
console.log(arr); / / [2]
/ / equivalent to the
var arr1 = arr.filter(index= >index ! = =1);
console.log(arr1) / / [2]
Copy the code

forCirculation andforEachPerformance difference of

For performance comparisons, we add a Map iterator, which generates new arrays just like the filter. For > forEach > Map in Chrome 62 and Node.js v9.1.0: The for loop is twice as fast as forEach, and forEach is about 20% faster than Map. Reason analysis for: The for loop has no additional function call stack or context, so it is the easiest to implement. ForEach: For forEach, its function signature contains parameters and context, so performance is lower than for loops. Map: The reason map is the slowest is that the map returns a new array, and the creation and assignment of an array results in the allocation of memory, thus incurs a high performance overhead. Nesting a map in a loop leads to more unnecessary memory consumption. When iterators are used to traverse an array, it is against design to use a map without returning a new array. I’ve seen a lot of people use maps just to iterate through groups of numbers in front-end co-development:

let data = []; Let data2 = [1, 2, 3]; data2.map(item=>data.push(item));Copy the code

At the end: This was a question I had in an interview, knowing only the grammar difference. Instead of further differentiating the similarities and differences in terms of iterables, iterators, generators, and performance, I wish I could have taken a simple problem and explained it in more detail so that you could understand it better.


If this article can help or inspire you, it will be my pleasure