EduFlow
JavaScript Fundamentals
0%

Section 3 · Working with Data

Arrays and Their Everyday Methods

18 min3 min readCode playground

Lesson at a glance

Create and change arrays, know which methods mutate them, and replace hand-written loops with map, filter, find, some and every to transform and search lists.

  1. 1Making and changing arrays
  2. 2map: transform every item
  3. 3filter: keep only some items
  4. 4find, some and every: searching
  5. 5Chaining: reading a pipeline

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Pocket’s expenses are a list, and almost every feature is a question about that list. Which ones are refunds? What do they look like formatted as dollars? Is there anything over $100? You can answer all of these with the loops from section 2, but arrays come with methods that answer them in one readable line each.

Making and changing arrays

An array is an ordered list of values. You saw the basics already: square brackets, positions from 0, and length.

JavaScript
const amounts = [450, 1220, 270];

amounts.push(899);           // add to the end
console.log(amounts);
const last = amounts.pop();  // remove from the end, and get it back
console.log(last, amounts);
amounts[0] = 500;            // replace an item by index
console.log(amounts, amounts.includes(1220), amounts.indexOf(270));

Wait: amounts is a const, yet it changed three times. That is not a contradiction. const means the name always points at the same array. It says nothing about what is inside the array. push, pop and index assignment all change the contents of that one array, so they are allowed. Only amounts = [...], pointing the name at a different array, would throw.

The const name amounts points to one array. push changes the items inside that array, which is allowed. Pointing amounts at a different array is what const forbids. const amounts [450, 1220, 270, 899] push / pop / [0] = … change this box: allowed re-pointing this arrow: TypeError
const fixes the arrow, not the contents

This idea, that a name points at a list and several operations change the list itself, is the reason to know which methods mutate:

Changes the array Returns something new, array untouched
push, pop, shift, unshift slice, concat
splice map, filter
sort, reverse toSorted, toReversed

Mutating is not wrong, but it surprises people when two parts of a program share one array. The methods in the rest of this lesson never mutate, which is a large part of why they are so popular.

The pair that confuses everyone is slice and splice, one letter apart and opposite in behaviour:

JavaScript
const amounts = [450, 1220, 270, 899];

const firstTwo = amounts.slice(0, 2);   // copy of indexes 0 and 1
console.log(firstTwo, amounts);         // original untouched

const removed = amounts.splice(1, 1);   // remove 1 item at index 1
console.log(removed, amounts);          // original changed

slice(start, end) works exactly like the string method of the same name: it copies a piece and leaves the original alone. splice(start, count) cuts items out of the array itself and returns what it removed. If you ever need to remove an item without changing the original, use filter instead, which you are about to meet.

map: transform every item

map calls a function for each item and collects the return values into a new array of the same length:

JavaScript
const amounts = [450, 1220, 270];
const formatMoney = (cents) => `${(cents / 100).toFixed(2)}`;

const labels = amounts.map(formatMoney);
console.log(labels);
console.log(amounts);  // unchanged

It is the built-in version of the applyToAll function you wrote in the functions lesson. Use map whenever the question is “turn each X into a Y”: cents into dollar strings, dollars into cents, raw form values into clean ones. The callback receives each item in turn and must return the new version of it. Whatever it returns lands at the same position in the result, so the output always has exactly as many items as the input.

filter: keep only some items

filter calls a test function for each item and returns a new array of only the items for which the test returned a truthy value:

JavaScript
const amounts = [450, -300, 1220, -50, 270];
const spending = amounts.filter((a) => a > 0);
const refunds = amounts.filter((a) => a < 0);
console.log(spending, refunds);

The result can be shorter than the original, or even empty, but filter never changes the items themselves.

find, some and every: searching

Four methods answer search questions, and each stops as soon as it knows the answer:

JavaScript
const amounts = [450, 12000, 1220, 15000];

console.log(amounts.find((a) => a >= 10000));       // first match: 12000
console.log(amounts.findIndex((a) => a >= 10000));  // its position: 1
console.log(amounts.some((a) => a < 0));            // any refunds? false
console.log(amounts.every((a) => a > 0));           // all positive? true

find returns the item itself, or undefined if nothing matches. findIndex returns its position, or -1. some and every return booleans: “at least one” and “all of them”.

Chaining: reading a pipeline

Because filter and map both return arrays, you can call one on the result of the other:

JavaScript
const amounts = [450, -300, 12000, 1220];
const bigOnes = amounts
  .filter((a) => a >= 1000)
  .map((a) => `${(a / 100).toFixed(2)}`);
console.log(bigOnes);

Read it top to bottom like a recipe: start with all amounts, keep the ones of $10 or more, format them. Each step gets the previous step’s output. Putting each step on its own line, starting with the dot, keeps long chains readable.

So far the arrays hold plain numbers. Real expenses have a label, an amount and a category together, which calls for objects, the subject of the next lesson.

Key takeaways

  • const stops a name from pointing at a different array, but the array’s contents can still change with push, pop or index assignment.
  • Some methods mutate the array (push, pop, splice, sort); others return a new value and leave it untouched (slice, map, filter).
  • map returns a new array of the same length with each item transformed; filter returns a new array of only the items that pass a test.
  • find returns the first matching item or undefined; some and every answer yes/no questions about the whole list.

Further reading

Check your understanding

4 questions

Question 1 of 4

What does this log?

JavaScript
const amounts = [450, 1220];
amounts.push(270);
console.log(amounts.length);
Question 2 of 4

const amounts = [450, -300, 1220]; What does amounts.find((a) => a > 5000) return?

Question 3 of 4

What does this log?

JavaScript
const out = [450, 1220].map((c) => {
  c / 100;
});
console.log(out);
Question 4 of 4

You need to know whether every expense in a list has a category. Which method fits?

Practice

Code playground

Ask questions about a list

Fill in four functions using array methods instead of for loops. None of them may change the array they receive.

  • spendingOnly(amounts) returns a new array with only the positive amounts.
  • formatAll(amounts) returns every amount formatted with the provided formatMoney.
  • firstBig(amounts) returns the first amount of 10000 cents or more, or undefined.
  • hasRefund(amounts) returns true if any amount is negative.
const amounts = [450, -300, 12000, 1220, -50, 15000];
const formatMoney = (cents) => `${(cents / 100).toFixed(2)}`;

// Use array methods, not for loops, and never change the array you receive.

// Only the positive amounts
function spendingOnly(amounts) {
  return amounts;
}

// Every amount formatted with formatMoney
function formatAll(amounts) {
}

// The first amount of 10000 cents or more, or undefined
function firstBig(amounts) {
}

// true if any amount is negative
function hasRefund(amounts) {
  return false;
}

console.log(spendingOnly(amounts), formatAll(amounts));
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

Console

(no output)

Checks

  • spendingOnly returns only positive amounts
  • formatAll formats every amount
  • firstBig returns the first amount of 10000 or more, or undefined
  • hasRefund detects negative amounts
  • None of the functions change the input array