Talk about the differences between loops in JavaScript in detail
- 2021-11-13 00:42:44
- OfStack
forEach and map methods Chain call
Performance
Conclusion
Preface
When using loops in JavaScript, you need to define two key things correctly: enumerable properties (enumerable properties) and iterative objects (iterable objects).
Enumerable properties
One defining feature of an enumerable object is that when we assign a property to the object through the assignment operator, we set the internal enumerable flag (enumerable) to true. This is the default value.
However, we can change this behavior by setting it to false.
The rule of thumb is that enumerable attributes always appear in the for... in loop.
Let's look at this one point:
const users = {}
users.languages = 'JavaScript'
Object.getOwnPropertyDescriptor(users, 'languages')
// output -> { value: 'JavaScript', writable: true, enumerable: true, configurable: true }
// More control over the attributes we use in the loop
Object.defineProperty(users, 'role', { value: 'Admin', writable: true, enumerable: false })
for (const item in users) {
console.log(item) // languages
}
As you can see, we added an languages attribute to the users variable, and the enumerable attribute of the languages attribute descriptor is true using the Object. getOwnPropertyDescriptor method.
Using Object. defineProperty to add the role attribute and setting enumerable to false, the role attribute is not output in the for... in loop. That is, the properties in the for... in loop are enumerable properties.
Iterable object
An object is iterative if it defines its iterative behavior. In this example, the value that will be looped in the for... of construct will define its iterative behavior. Iterable built-in types including Array, String, Set, and Map objects are not iterable because it does not specify the @ iterator method.
Basically, in JavaScript, all iterative objects are enumerable objects, but not all enumerable objects are iterative objects.
Here is a conceptual approach: for... in looks for objects in the data, and for... of looks for repeats.
Let's look at the effect of this 1 cut when used with Array data type 1:
const languages = ['JavaScript', 'Python', 'Go']
// And for...in Cycle 1 Start using
for (const language in languages) {
console.log(language)
}
// output
// 0
// 1
// 2
// And for...of Cycle 1 Start using
for (const language of languages) {
console.log(author)
}
// output -> JavaScript Python Go
One thing to keep in mind when using this construct is that if typeof is called and the output is object, you can use the for... in loop.
Let's look at this operation on the languages variable:
typeof languages // "object" -> So we can use the for
At first glance, this may seem surprising, but it should be noted that an array is a special type of object with an index as its key. Knowing that for... in will look for objects in constructs can help us enormously. When the for... in loop finds an object, it loops over each key.
We can visualize the way for... in loops over an languages array as follows:
const languages = {
0: 'JavaScript',
1: 'Python',
2: 'Go'
}
Note: If it can be traced to 1 object (or inherited from the object prototype chain), for... in will traverse the keys in no particular order.
Also, if it implements one iterator for.. of construct, it loops through the value in each iteration.
forEach and map methods
Although the forEach and map methods can be used to achieve the same goal, their behavior and performance characteristics differ.
At the basic level, when functions are called, they all receive 1 callback as an argument.
Consider the following fragment:
const scoresEach = [2, 4 ,8, 16, 32]
const scoresMap = [2, 4 ,8, 16, 32]
const square = (num) => num * num
Let's introduce some differences in their operation in detail.
forEach returns undefined and map returns a new array:
let newScores = []
const resultWithEach = scoresEach.forEach(score => {
const newScore = square(score)
newScores.push(newScore)
})
const resultWithMap = scoresMap.map(square)
console.log(resultWithEach) // undefined
console.log(resultWithMap) // [4, 16, 64, 256, 1024]
Map is a pure function, while forEach performs one mutation:
console.log(newScores) // [4, 16, 64, 256, 1024]
In my opinion, map supports functional programming paradigm. We don't have to always perform mutations to get the desired results, unlike forEach, we have to mutate newScores variables. At each run, the map function produces the same result when the same input is supplied. At the same time, the forEach corresponding term will be extracted from the previous value of the previous mutation.
Chain call
Using map, you can make a chain call because the result returned is an array. Therefore, any other array method can be called immediately on the result. In other words, we can call filter, reduce, some, and so on. This is not possible in forEach because the value returned is undefined's.
Performance
The performance of map method is often better than that of forEach method.
Check the performance of equivalent code blocks implemented using map and forEach. On average, you will see that the map function executes at least 50% faster.
Conclusion
Of all the loop structures discussed above, the one that gives us the most control is the for... of loop. We can use it with the keywords return, continue, and break 1. This means that we can specify what happens to each element in the array and whether to leave or skip early.