Arrays in JavaScript: from simple lists to clean transformations

Last updated on
Arrays in JavaScript: from simple lists to clean transformations

Arrays are one of the most used data structures in JavaScript because they represent lists: products, posts, users, messages, tasks, API results, or table rows. They look easy at first, but in real projects the important skill is knowing when to mutate, when to create a copy, and which method communicates your intent best.

Creating arrays and reading values

The most common way to create an array is with brackets:

const fruits = ['apple', 'banana', 'orange'];

console.log(fruits[0]); // "apple"
console.log(fruits.length); // 3

Indexes start at 0, so the last item is at array.length - 1. You can also use at() to read from the end more clearly:

console.log(fruits.at(-1)); // "orange"

Mutating or not mutating

Some methods change the original array:

const numbers = [1, 2, 3];

numbers.push(4);
numbers.pop();
numbers.sort();

Other methods return a new array:

const numbers = [1, 2, 3];
const doubled = numbers.map((number) => number * 2);

console.log(numbers); // [1, 2, 3]
console.log(doubled); // [2, 4, 6]

This difference matters in frameworks like React, where you usually want new references so the UI can detect state changes correctly.

map, filter, and reduce

These three methods cover a large part of daily list work.

map() transforms every item:

const users = [
  { name: 'Ana', active: true },
  { name: 'Luis', active: false },
];

const names = users.map((user) => user.name);
console.log(names); // ["Ana", "Luis"]

filter() keeps only the items that match a condition:

const activeUsers = users.filter((user) => user.active);

reduce() accumulates a result. It is useful when you need a total or when you want to convert a list into another structure:

const cart = [
  { product: 'Keyboard', price: 80 },
  { product: 'Mouse', price: 40 },
];

const total = cart.reduce((sum, item) => sum + item.price, 0);
console.log(total); // 120

Do not use reduce() for everything. If map() or filter() makes the intent clearer, prefer them.

Finding items

To check whether a simple value exists, use includes():

const roles = ['admin', 'editor', 'reader'];
console.log(roles.includes('admin')); // true

For objects, use find() or some():

const posts = [
  { slug: 'arrays', published: true },
  { slug: 'draft', published: false },
];

const post = posts.find((item) => item.slug === 'arrays');
const hasDrafts = posts.some((item) => !item.published);

find() returns the item. some() returns a boolean. Choosing the right method makes the code read almost like a sentence.

Copies, slice, and spread

If you need to add or remove items without changing the original array, create a copy:

const original = ['React', 'Astro'];
const updated = [...original, 'Node.js'];

console.log(original); // ["React", "Astro"]
console.log(updated); // ["React", "Astro", "Node.js"]

slice() also returns a partial copy:

const firstTwo = updated.slice(0, 2);

This is more predictable than mutating a list shared across different parts of an application.

Sorting: be careful with sort

sort() mutates the array and converts values to strings if you do not pass a comparison function:

const numbers = [10, 2, 30];
console.log(numbers.sort()); // [10, 2, 30] as strings

For numbers:

const sorted = [...numbers].sort((a, b) => a - b);
console.log(sorted); // [2, 10, 30]

The copy with [...] avoids changing the original array.

Performance and readability

For small lists, prioritize clarity. For very large lists or code that runs many times per second, avoid walking the same list five times without a reason. Chaining filter().map().sort() is readable, but each step has a cost. If you suspect a real performance problem, measure first and optimize after that.

Best practices

  • Use map to transform, filter to select, and reduce to accumulate.
  • Avoid mutating shared arrays when the data feeds UI or state.
  • Use find when you need the item and some when you only need to know if it exists.
  • Copy before sorting if you do not want to modify the original array.
  • Do not use forEach when you need a new array; you probably want map.
  • Keep callbacks small and readable.

Conclusion

Arrays are much more than a list of values. Used well, they let you write clear and predictable data transformations. The quality jump happens when you choose methods by intent, control mutation, and make each operation explain what is happening to the data.