Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Use one loop for each array level. To change the existing nested arrays, assign to their elements; to produce a changed copy, return values from nested map() calls. Use forEach() for side effects, not to build a result. The right choice depends on whether you want to mutate, transform, stop early, or change the array’s shape.

How do you loop through an array of arrays?

An outer loop visits each inner array as a value. A second loop visits the elements inside that row. Keep the indices distinct: each belongs to a different nesting level.

const grid = [
  [1, 2],
  [3, 4],
];

for (let rowIndex = 0; rowIndex < grid.length; rowIndex++) {
  for (let columnIndex = 0; columnIndex < grid[rowIndex].length; columnIndex++) {
    console.log(rowIndex, columnIndex, grid[rowIndex][columnIndex]);
  }
}

Here, rowIndex selects an inner array and columnIndex selects a value within it. Using each row’s own length also works when rows have different sizes. For an explanation of JavaScript loop forms, see MDN’s loops and iteration guide.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do you change values in the existing nested array?

Assign to the desired element. A numeric loop is clear when the indices determine which values to update:

const grid = [
  [1, 2],
  [3, 4],
];

for (let rowIndex = 0; rowIndex < grid.length; rowIndex++) {
  for (let columnIndex = 0; columnIndex < grid[rowIndex].length; columnIndex++) {
    grid[rowIndex][columnIndex] *= 2;
  }
}

// grid is [[2, 4], [6, 8]]

This changes the existing rows and their values without changing the arrays’ lengths. A nested forEach() can also make these assignments, but its callback return values do not become a result:

const grid = [[1, 2], [3, 4]];

grid.forEach((row) => {
  row.forEach((value, columnIndex) => {
    row[columnIndex] = value * 2;
  });
});

forEach() returns undefined. The assignments above mutate the rows; the method itself does not create a transformed grid. It skips sparse holes but visits elements explicitly set to undefined. See MDN’s forEach() reference.

How do you create a transformed copy instead?

Return a value from each inner map(), then return that inner result from the outer callback. Each call creates an array at its own level:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const grid = [[1, 2], [3, 4]];
const doubled = grid.map((row) => row.map((value) => value * 2));

// grid:    [[1, 2], [3, 4]]
// doubled: [[2, 4], [6, 8]]

The original array remains unchanged here. Because this example contains numbers, the new nested arrays contain transformed values. If the elements are objects, nested map() alone does not deep-clone those objects; references to them may still be shared. Use map() when you need its returned array, rather than calling it for side effects and discarding that result. See MDN’s map() reference.

Which approach should you choose?

Goal Approach Effect
Change an existing value by index Nested numeric for loops Assignments mutate the existing array; indices are explicit.
Perform an action for each visited value Nested forEach() calls Useful for side effects; callback results are discarded and the method returns undefined.
Build a transformed nested structure Nested map() calls Returns new arrays at the mapped levels; return the inner result from the outer callback.
Remove or keep selected elements filter() at the relevant level Builds a filtered result rather than shifting elements during forward traversal.
Stop when a condition is met for, for...of, or a short-circuiting method such as some() Supports early termination; forEach() does not support a normal break.
Flatten one nesting level flat() Returns a shallow array and removes the selected level of nesting.

What happens if an array changes while you iterate?

Array iterative methods such as forEach() and map() capture the array’s length when the method starts. They check indices up to that starting length, but read each value when its index is reached. As a result:

  • Appending beyond the initial length does not make these methods visit the appended element.
  • Changing an unvisited index can change the value the callback receives there.
  • Deleting an unvisited element means that index is skipped.

These effects can make traversal difficult to reason about; avoid changing array contents or length during these callbacks unless the behavior is intentional. MDN describes this behavior in its Array reference.

for...of uses the array iterator, which reads the current length as it advances. Appending during the loop can therefore cause added elements to be visited; if each iteration appends another element, the loop may never finish. The iterator behavior is documented in MDN’s values() reference.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Removing elements safely

Removing the current element with splice() in a forward numeric loop shifts later elements left. The loop then advances, potentially skipping the element that shifted into the removed element’s position. If the original structure should be preserved, build a filtered result with filter() at the appropriate nesting level instead of splicing during traversal.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Does flat() modify the nested array?

No. flat() returns a new shallow array and leaves the source unchanged. Its default depth is one:

const nested = [1, [2, 3], [4, [5]]];
const oneLevel = nested.flat();

// oneLevel is [1, 2, 3, 4, [5]]

The inner array containing 5 remains nested because the default operation flattens only one level. Flattening is a shape change, not a way to update values in place. See MDN’s flat() reference.

Common mistakes to avoid

  • Expecting map() to change the original: it returns a new array. Store the result or use explicit assignments if you intend to mutate.
  • Returning a value from forEach() and expecting an array: callback results are discarded, and forEach() returns undefined.
  • Using forEach() when you need break: it cannot be stopped through ordinary loop control. Use a loop or a short-circuiting method instead.
  • Using for...in for array values: it enumerates property names and can include extra enumerable properties. Use an array loop, for...of, or an array method suited to the task.
  • Assuming a hole equals undefined: forEach() skips an unassigned sparse slot, but visits a slot explicitly assigned undefined.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.