Working with Arrays
Working with Arrays
Arrays are ordered collections of data — a shopping list, a set of scores, rows from a database. Almost every real program loops over, filters, or reshapes an array somewhere, so the methods in this tutorial are the ones you will use daily as a JavaScript developer.
Step 1: Creating Arrays
// Array literal — use this 99% of the time
const fruits = ["apple", "banana", "orange"];
// Array.from() builds an array from anything iterable
const chars = Array.from("hello"); // ["h", "e", "l", "l", "o"]
// Array.of() avoids the constructor's quirk
const nums = Array.of(3); // [3]
const trap = new Array(3); // [empty x 3] — three EMPTY slots, not [3]!
Why the literal is preferred: new Array(3) with a single number creates a sparse array of that length, not an array containing the number. The literal syntax has no such surprise, which is why style guides recommend it.
Step 2: Adding and Removing Elements
const arr = [1, 2, 3];
arr.push(4); // [1, 2, 3, 4] — add to end, returns new length
arr.pop(); // [1, 2, 3] — remove from end, returns removed item
arr.unshift(0); // [0, 1, 2, 3] — add to start
arr.shift(); // [1, 2, 3] — remove from start
Why it works with const: const arr locks the variable binding, not the array's contents, so mutating methods are fine. Also note that push/pop are fast, while shift/unshift must re-index every element — avoid them inside large loops.
Step 3: The Big Three — map, filter, reduce
These three methods replace most manual loops, and none of them modifies the original array:
const numbers = [1, 2, 3, 4, 5];
// map: transform EVERY element, same length out
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8, 10]
// filter: keep elements that pass the test
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
// reduce: fold everything into ONE value
const sum = numbers.reduce((acc, n) => acc + n, 0); // 15
Why it works: each method visits elements left to right and calls your function. map collects the return values into a new array; filter collects elements whose callback returned something truthy; reduce threads an accumulator through every call — acc starts at the second argument (0 here) and becomes whatever your callback returns each round. Forgetting that initial value is a classic bug: without it, reduce uses the first element as the accumulator, which breaks on empty arrays.
You can chain them, and the pipeline reads like a sentence:
const cart = [
{ name: "Pen", price: 2, qty: 3 },
{ name: "Book", price: 12, qty: 1 },
{ name: "Bag", price: 25, qty: 0 }
];
const total = cart
.filter(item => item.qty > 0)
.map(item => item.price * item.qty)
.reduce((acc, n) => acc + n, 0);
console.log(total); // 18
Step 4: Finding Things
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
users.find(u => u.id === 1); // { id: 1, name: "Alice" }
users.findIndex(u => u.name === "Bob"); // 1
users.some(u => u.id > 1); // true — at least one matches?
users.every(u => u.id > 0); // true — do ALL match?
users.map(u => u.name).includes("Alice"); // true
find returns undefined when nothing matches — always handle that case before reading properties off the result.
Step 5: Copying and Combining with Spread
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
const copy = [...arr1]; // a NEW array with the same items
Why copying matters: const copy = arr1 does not copy anything — both names point at the same array, so changing one "changes" the other. Spread creates a genuinely new array. It is a shallow copy though: nested objects inside are still shared.
Common Beginner Errors and Fixes
- Expecting map or filter to change the original array. They never do; they return a new one. Fix: assign the result —
items = items.filter(...). - Returning nothing from a map callback when using
{ }braces:numbers.map(n => { n * 2 })produces[undefined, undefined, ...]. Fix: addreturn, or drop the braces. - Using forEach and trying to collect results.
forEachalways returnsundefined. Fix: usemapwhen you need output. - Off-by-one on length: the last index is
arr.length - 1, soarr[arr.length]isundefined. Fix: usearr.at(-1)for the last element. - Removing items while looping forward skips elements, because indexes shift underneath you. Fix: use
filterto build the array you want instead of deleting in place.
Practice Exercise
You are given daily step counts: const steps = [4200, 11050, 8600, 300, 9999, 12480];
Math.round).reduce.Expected output: 4 qualifying days, and a total of about 30 km. Try to write it as one filter → map → reduce chain — then try again with a single reduce and compare which version you find more readable.