Best Practices for Iteration in JavaScript
This article explains the best practices for iteration in JavaScript.
YouTube Video
Best Practices for Iteration in JavaScript
In JavaScript, it is common to use for
loops for iteration. Here, we will provide a detailed explanation of the best practices for using for
loops to write efficient and readable code.
Choose the Right Looping Structure
JavaScript provides multiple looping constructs, each suited for different purposes.
1// Example of a for loop
2for (let i = 0; i < 5; i++) {
3 console.log(i);
4}
5
6// Example of a for...of loop
7const array = [10, 20, 30];
8for (const value of array) {
9 console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15 console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21 console.log(count);
22 count++;
23}
for
statement is suitable when the number of iterations is predetermined.for...of
statement is suitable for concisely processing arrays and iterable objects.for...in
statement is used to iterate over an object's properties. However, it is not suitable for arrays.while
statement anddo...while
statement are used to control loops based on conditions.
Utilizing the forEach
method and for...of
statement
When looping through an array, using a for
statement to access the index is common, but the forEach
method or for...of
statement may be more readable.
1// Using a standard for loop
2const array = ["apple", "banana", "cherry"];
3for (let i = 0; i < array.length; i++) {
4 console.log(array[i]);
5}
6
7// Using forEach
8array.forEach(item => console.log(item));
9
10// Using for...of
11for (const item of array) {
12 console.log(item);
13}
for
statement allows explicit index management while iterating.forEach
method uses a callback function to process each element concisely.for...of
statement is highly readable and allows direct access to each element in an array.
Optimize Loop Conditions
Since the loop condition is evaluated repeatedly, avoiding unnecessary computations can improve performance.
1const names = ["Alice", "Bob", "Charlie"];
2const scores = [85, 92, 78];
3
4// Inefficient example
5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
6 console.log(`${names[i]} scored ${scores[i]}`);
7}
8
9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11 console.log(`${names[i]} scored ${scores[i]}`);
12}
- As shown in this example, storing the calculation result in a variable beforehand allows for more efficient loop execution.
1const scores = [85, 92, 78];
2let sum = 0;
3let sum2 = 0;
4
5// Inefficient example
6for (let i = 0; i < scores.length; i++) {
7 sum += scores[i];
8}
9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13 sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);
- As shown in this example, reversing the condition can sometimes be more efficient.
Optimizing Loop Processing
Since loop processing is executed repeatedly, avoiding unnecessary calculations can improve performance.
1const array = ["apple", "banana", "cherry"];
2
3// Inefficient example
4for (let i = 0; i < 100; i++) {
5 const element = document.querySelector("#myElement");
6 element.textContent = `Count: ${i}`;
7}
8
9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12 element.textContent = `Count: ${i}`;
13}
- In this example, by moving the
querySelector
method outside the loop, unnecessary repeated calculations are eliminated.
Be Aware of Scope
Use let
or const
to ensure variables inside the loop have appropriate scope. Since var
is limited to function scope, it may cause unexpected behavior.
1// Using let
2for (let i = 0; i < 3; i++) {
3 console.log(i);
4}
5
6// Potential issue with var
7for (var i = 0; i < 3; i++) {
8 setTimeout(() => console.log(i), 1000); // 3, 3, 3
9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13 setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}
var
has function scope, so after the loopi
is3
, and all functions executed bysetTimeout
output3
.- Using
let
, thei
inside thesetTimeout
callback function refers to a new value for each loop, so0, 1, 2
are output as expected.
Improve Readability with Early Exits
To simplify loop processing, use break
and continue
appropriately to enhance readability.
1// Example using break
2for (let i = 0; i < 10; i++) {
3 if (i === 5) {
4 break; // Exit the loop
5 }
6 console.log(i);
7}
8
9// Example using continue
10for (let i = 0; i < 10; i++) {
11 if (i % 2 === 0) {
12 continue; // Skip to the next iteration
13 }
14 console.log(i);
15}
- Using
break
allows you to terminate loop processing midway, skipping all subsequent iterations. - Using
continue
allows you to skip the current loop process and move to the next iteration.
Avoid Deep Nesting
Deep nesting makes code harder to read, so aim to keep nesting shallow by using early returns or splitting functionality into functions.
1// Deeply nested example
2for (let i = 0; i < 5; i++) {
3 for (let j = 0; j < 5; j++) {
4 if (i + j > 5) {
5 console.log(i, j);
6 }
7 }
8}
9
10// Improved using function decomposition
11function processPairs(i) {
12 for (let j = 0; j < 5; j++) {
13 if (i + j > 5) {
14 console.log(i, j);
15 }
16 }
17}
18
19for (let i = 0; i < 5; i++) {
20 processPairs(i);
21}
- In this example, functions are used to reduce nesting.
Consider error handling
If there is a possibility of errors occurring within the loop, implement proper error handling.
1const data = ["123", "abc", "456", "xyz"];
2
3// Without Error Handling
4for (const item of data) {
5 const result = parseInt(item);
6 console.log(`Parsed value: ${result}`);
7}
8
9// With Error Handling
10for (const item of data) {
11 try {
12 const result = parseInt(item);
13 if (isNaN(result)) {
14 throw new Error(`Invalid number: ${item}`);
15 }
16 console.log(`Parsed value: ${result}`);
17 } catch (error) {
18 console.error(`Error processing item: ${item}. ${error.message}`);
19 }
20}
- In this example, error handling is performed for processing invalid data, detecting and reporting issues.
Points to note in asynchronous processing
When handling asynchronous processing in loops, using async/await
can result in concise and intuitive code.
1const urls = ["https://example.com/1", "https://example.com/2"];
2
3// Proper handling of asynchronous operations
4async function fetchUrls() {
5 for (const url of urls) {
6 const response = await fetch(url);
7 const data = await response.json();
8 console.log(data);
9 }
10}
11
12fetchUrls();
- This code asynchronously fetches URLs from the
urls
array one by one and processes the results in JSON format. Usingasync/await
simplifies asynchronous operations, sequentially retrieving data for each URL and outputting it to the console.
Understand the difference between for...of
statement and forEach()
in asynchronous processing
1async function asyncTask(num) {
2 return new Promise(resolve => {
3 setTimeout(() => {
4 console.log(`Task ${num} done`);
5 resolve();
6 }, 100);
7 });
8}
9
10async function runWithForOf() {
11 console.log("Start for...of");
12 for (const num of [1, 2, 3]) {
13 await asyncTask(num);
14 }
15 console.log("End for...of");
16}
17
18async function runWithForEach() {
19 console.log("Start forEach");
20 [1, 2, 3].forEach(async num => {
21 await asyncTask(num);
22 });
23 console.log("End forEach");
24}
25
26async function executeExamples() {
27 await runWithForOf();
28 await runWithForEach();
29}
30
31executeExamples();
-
When handling asynchronous processing in loops, note the differences in behavior, as shown in this example, between using
for...of
withasync/await
and usingforEach()
. -
With
for...of
, the code executes sequentially and waits at theawait
inside the loop before continuing to the next iteration. On the other hand,forEach()
executes the processing in parallel.
Conclusion
The for
statement in JavaScript is a simple yet powerful tool. By leveraging the best practices introduced here, you can write efficient and highly readable code. Pay attention to selecting appropriate loop constructs, scope management, error handling, and aim for highly maintainable code.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.