Overview
forEach()
is a prototype method of an array object, which executes a given callback function once for each element in the array, and always returns undefined. Array-like objects do not have a forEach
method, such as arguments. The usage of forEach
is relatively simple:
|
|
Parameter explanation:
callback
: The callback function to be executed for every element in the array, can have 1–3 parameters
currentValue
: The current element being processed, requiredindex
: The index of the current element being processed, optionalarray
: The original array object that the forEach method operates on, optional
thisArg
: The this context of the callback function during execution, defaults to the global object, optional
Note
First: Does not support handling asynchronous functions
The forEach()
method in JavaScript is a synchronous method and does not support handling asynchronous functions. If you execute an asynchronous function within forEach
, forEach()
does not wait for the asynchronous function to complete; it proceeds to the next item. This means that if you use asynchronous functions within forEach()
, the execution order of asynchronous tasks cannot be guaranteed.
|
|
Solve
- Method One
You can use methods such as map()
, filter()
, reduce()
, etc., which support returning a Promise in the function and will wait for all Promises to complete.
Here is an example code of using map()
and Promise.all()
to handle asynchronous functions:
|
|
Since we used the await keyword in the asynchronous function, the map()
method will wait for the asynchronous function to complete and return a result, so we can correctly handle asynchronous functions.
- Method Two
Using a for loop to handle asynchronous functions.
|
|
Second: Cannot catch errors in asynchronous functions
If an asynchronous function throws an error during execution, forEach()
cannot catch that error. This means that even if an error occurs in the asynchronous function, forEach()
will still proceed.
Third: Apart from throwing an exception, there is no way to terminate or break out of a forEach() loop
The forEach()
method does not support using break or continue statements to jump out of the loop or skip an item. If you need to break out of the loop or skip an item, you should use a for loop or other methods that support break or continue statements.
|
|
Fourth: Deleting its own element, the index cannot be reset
In forEach, we can’t control the value of the index; it just increments blindly until it exceeds the length of the array and exits the loop. Therefore, it’s also impossible to delete itself to reset the index. Let’s look at a simple example.
|
|
Fifth: Issue with the ‘this’ context
In the forEach()
method, the this keyword refers to the object that calls the method. However, when using a regular function or an arrow function as the parameter, the scope of the this keyword might face issues. In arrow functions, the this keyword refers to the object in which the function was defined. In regular functions, the this keyword refers to the object that calls the function. To ensure the correct scope for the this keyword, the bind()
method can be used to bind the function’s scope. Here’s an example illustrating the issue of the this keyword scope in the forEach()
method:
|
|
In this example, we defined an object named obj with a printFriends() method. Inside the printFriends() method, we use the forEach() method to iterate over the friends array and use a regular function to print each friend’s name and obj object’s name property. However, upon running this code, the output will show:
|
|
This is because, within the forEach()
method when using a regular function, the scope of the function is not the object calling the printFriends()
method but the global scope. Hence, the obj object’s properties are not accessible within that function.
To solve this problem, the bind()
method can be used to bind the function’s scope, or an arrow function can be used to define the callback function. Here’s an example of solving the issue using the bind()
method:
|
|
In this example, we use the bind() method to bind the function’s scope, tying its scope to the obj object. After running the code, the output is:
|
|
By binding the function’s scope using the bind()
method, we can access the properties of the obj object correctly.
Another solution is to use an arrow function. Since an arrow function does not have its own this, it inherits the this from its current scope. Hence, in an arrow function, the this keyword refers to the object in which the function was defined. The code is omitted for brevity.
Sixth: forEach has lower performance than for loop
for
: The for loop doesn’t have extra function call stacks and context, so its implementation is the simplest.forEach
: For forEach, its function signature includes parameters and context, so its performance is lower than the for loop.
Seventh: Skips over deleted or uninitialized items
|
|
Eighth: Does not change the original array
When forEach()
is called, it does not change the original array, which is the array it was called on. However, the object may be changed by the callback function passed in.
|
|