JavaScript BasicsFeatured

JavaScript forEach(): Complete Guide to Array Iteration

Master the JavaScript forEach() method for array iteration. Learn syntax, use cases, comparisons with other loops, and best practices with examples.

By JavaScriptDoc Team
forEacharraysiterationloopsjavascript

JavaScript forEach(): Complete Guide to Array Iteration

The forEach() method executes a provided function once for each array element. It's one of the most commonly used methods for iterating over arrays in JavaScript.

Understanding forEach()

// Basic syntax
array.forEach(function (element, index, array) {
  // Code to execute for each element
});

// Arrow function syntax
array.forEach((element, index, array) => {
  // Code to execute for each element
});

Basic Examples

// Simple iteration
const numbers = [1, 2, 3, 4, 5];
numbers.forEach((num) => {
  console.log(num);
});
// Output: 1, 2, 3, 4, 5

// Using all parameters
const fruits = ['apple', 'banana', 'orange'];
fruits.forEach((fruit, index, array) => {
  console.log(`${index}: ${fruit} from array of length ${array.length}`);
});
// 0: apple from array of length 3
// 1: banana from array of length 3
// 2: orange from array of length 3

Common Use Cases

DOM Manipulation

// Update multiple elements
const buttons = document.querySelectorAll('button');
buttons.forEach((button) => {
  button.addEventListener('click', () => {
    button.classList.toggle('active');
  });
});

// Process form inputs
const inputs = document.querySelectorAll('input[type="text"]');
inputs.forEach((input) => {
  input.value = input.value.trim();
});

Data Processing

// Calculate totals
const prices = [29.99, 45.5, 12.0, 78.25];
let total = 0;
prices.forEach((price) => {
  total += price;
});
console.log(`Total: $${total.toFixed(2)}`); // Total: $165.74

// Update object properties
const users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 25 },
  { name: 'Bob', age: 35 },
];

users.forEach((user) => {
  user.isAdult = user.age >= 18;
  user.ageGroup = user.age < 30 ? 'young' : 'adult';
});

forEach() vs Other Iteration Methods

forEach() vs map()

const numbers = [1, 2, 3, 4, 5];

// forEach - no return value, used for side effects
const squared1 = [];
numbers.forEach((num) => {
  squared1.push(num ** 2);
});

// map - returns new array, used for transformation
const squared2 = numbers.map((num) => num ** 2);

console.log(squared1); // [1, 4, 9, 16, 25]
console.log(squared2); // [1, 4, 9, 16, 25]

forEach() vs for Loop

const items = ['a', 'b', 'c', 'd'];

// Traditional for loop - can break/continue
for (let i = 0; i < items.length; i++) {
  if (items[i] === 'c') break;
  console.log(items[i]);
}
// Output: a, b

// forEach - cannot break
items.forEach((item) => {
  if (item === 'c') return; // Only skips current iteration
  console.log(item);
});
// Output: a, b, d

forEach() vs for...of

const colors = ['red', 'green', 'blue'];

// for...of - can break/continue, works with any iterable
for (const color of colors) {
  if (color === 'green') continue;
  console.log(color);
}

// forEach - array method only
colors.forEach((color) => {
  if (color === 'green') return;
  console.log(color);
});

Working with Objects

// Iterating over object values
const person = {
  name: 'John',
  age: 30,
  city: 'New York',
};

Object.keys(person).forEach((key) => {
  console.log(`${key}: ${person[key]}`);
});

Object.values(person).forEach((value) => {
  console.log(value);
});

Object.entries(person).forEach(([key, value]) => {
  console.log(`${key}: ${value}`);
});

Async Operations in forEach

// Problem: forEach doesn't wait for async operations
const urls = ['url1', 'url2', 'url3'];

// This doesn't work as expected
urls.forEach(async (url) => {
  const response = await fetch(url);
  console.log(response);
});
console.log('Done'); // Logs before fetches complete

// Solution 1: Use for...of
async function fetchAll() {
  for (const url of urls) {
    const response = await fetch(url);
    console.log(response);
  }
  console.log('Done');
}

// Solution 2: Use Promise.all with map
async function fetchAllParallel() {
  await Promise.all(urls.map((url) => fetch(url)));
  console.log('Done');
}

Modifying Arrays During Iteration

// Adding elements
const numbers = [1, 2, 3];
numbers.forEach((num, index) => {
  if (num === 2) {
    numbers.push(4); // New element won't be visited
  }
  console.log(num);
});
// Output: 1, 2, 3

// Removing elements (not recommended)
const items = [1, 2, 3, 4, 5];
items.forEach((item, index) => {
  if (item === 3) {
    items.splice(index, 1); // Can cause skipping
  }
});
console.log(items); // [1, 2, 4, 5]

Practical Examples

Form Validation

function validateForm(formElement) {
  const errors = [];
  const inputs = formElement.querySelectorAll('input[required]');

  inputs.forEach((input) => {
    if (!input.value.trim()) {
      errors.push({
        field: input.name,
        message: `${input.name} is required`,
      });
      input.classList.add('error');
    } else {
      input.classList.remove('error');
    }
  });

  return errors;
}

Shopping Cart

class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(item) {
    this.items.push(item);
  }

  calculateTotal() {
    let total = 0;
    this.items.forEach((item) => {
      total += item.price * item.quantity;
    });
    return total;
  }

  applyDiscount(percent) {
    this.items.forEach((item) => {
      item.price *= 1 - percent / 100;
    });
  }

  displayItems() {
    console.log('Shopping Cart:');
    this.items.forEach((item, index) => {
      console.log(
        `${index + 1}. ${item.name} - $${item.price} x ${item.quantity}`
      );
    });
  }
}

Data Transformation

// Process API response
const apiResponse = [
  { id: 1, first_name: 'John', last_name: 'Doe', active: 1 },
  { id: 2, first_name: 'Jane', last_name: 'Smith', active: 0 },
];

const users = [];
apiResponse.forEach((userData) => {
  users.push({
    id: userData.id,
    fullName: `${userData.first_name} ${userData.last_name}`,
    isActive: Boolean(userData.active),
  });
});

Performance Considerations

// Performance comparison
const largeArray = Array(1000000).fill(1);

// forEach
console.time('forEach');
let sum1 = 0;
largeArray.forEach((num) => {
  sum1 += num;
});
console.timeEnd('forEach');

// for loop (typically faster)
console.time('for');
let sum2 = 0;
for (let i = 0; i < largeArray.length; i++) {
  sum2 += largeArray[i];
}
console.timeEnd('for');

// for...of
console.time('for...of');
let sum3 = 0;
for (const num of largeArray) {
  sum3 += num;
}
console.timeEnd('for...of');

Common Pitfalls

Return Value

// forEach always returns undefined
const numbers = [1, 2, 3];
const result = numbers.forEach((num) => num * 2);
console.log(result); // undefined

// Use map for transformation
const doubled = numbers.map((num) => num * 2);
console.log(doubled); // [2, 4, 6]

Breaking Out

// Cannot use break or continue
const numbers = [1, 2, 3, 4, 5];

// This doesn't work
// numbers.forEach(num => {
//   if (num === 3) break; // SyntaxError
// });

// Alternatives
// 1. Use for loop or for...of
for (const num of numbers) {
  if (num === 3) break;
  console.log(num);
}

// 2. Use some() or every()
numbers.some((num) => {
  if (num === 3) return true; // Breaks
  console.log(num);
});

// 3. Throw exception (not recommended)
try {
  numbers.forEach((num) => {
    if (num === 3) throw new Error('Break');
    console.log(num);
  });
} catch (e) {
  // Stopped
}

this Context

// Arrow functions
const obj = {
  multiplier: 2,
  numbers: [1, 2, 3],

  // Works with arrow function
  multiplyAll() {
    this.numbers.forEach((num) => {
      console.log(num * this.multiplier);
    });
  },
};

// Traditional function requires binding
const obj2 = {
  multiplier: 2,
  numbers: [1, 2, 3],

  multiplyAll() {
    this.numbers.forEach(function (num) {
      console.log(num * this.multiplier); // undefined
    });
  },
};

// Solutions for traditional functions
// 1. Bind this
this.numbers.forEach(
  function (num) {
    console.log(num * this.multiplier);
  }.bind(this)
);

// 2. Store this
const self = this;
this.numbers.forEach(function (num) {
  console.log(num * self.multiplier);
});

// 3. Pass thisArg
this.numbers.forEach(function (num) {
  console.log(num * this.multiplier);
}, this);

Best Practices

1. Use forEach for Side Effects

// Good use cases
const logs = [];
data.forEach((item) => {
  logs.push(`Processed: ${item.id}`);
  updateDatabase(item);
  sendNotification(item);
});

2. Prefer map() for Transformation

// Not ideal
const squared = [];
numbers.forEach((n) => squared.push(n ** 2));

// Better
const squared = numbers.map((n) => n ** 2);

3. Consider for...of for Breakable Loops

// When you need to break
for (const item of items) {
  if (shouldStop(item)) break;
  process(item);
}

4. Handle Empty Arrays

const items = [];
items.forEach((item) => {
  console.log(item); // Never executes
});
// No error, just does nothing

Conclusion

The forEach() method is perfect for executing side effects on array elements. Key points:

  • Executes a function for each array element
  • Cannot break out of the loop
  • Always returns undefined
  • Great for DOM manipulation and side effects
  • Use map() for transformations
  • Use for...of when you need to break

Choose forEach() when you need to perform actions on each element without creating a new array or breaking early!