Arrays and Array Methods
Objectives
By the end of this chapter, you should be able to:
- Create arrays and access items by index
- Use
.lengthto find how many items an array holds - Add and remove items with
.push()and.pop() - Check for a value with
.includes()and find its position with.indexOf() - Copy out part of an array with
.slice() - Use
.map(),.filter(),.find(), and.reduce()to transform and summarize arrays
💡 Why this matters: Almost any real data is a list: a shopping cart, a set of search results, the students in a class. Arrays are how JavaScript stores ordered lists, and array methods are how you work with them without writing a manual loop every time.
Creating Arrays and Accessing Items
An array is an ordered list of values, written with square brackets and separated by commas.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits);
// [ 'apple', 'banana', 'cherry' ]
Each item has a position, called an index, starting at 0.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits[0]);
// apple
console.log(fruits[2]);
// cherry
Asking for an index that doesn’t exist doesn’t error, it returns undefined.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits[10]);
// undefined
.length
.length tells you how many items an array holds.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits.length);
// 3
Because indexes start at 0, the last item is always at length - 1.
const fruits = ["apple", "banana", "cherry"];
console.log(fruits[fruits.length - 1]);
// cherry
Adding and Removing: .push() and .pop()
.push() adds one or more items to the end of an array. It changes the original array.
const queue = ["Erin", "Jordan"];
queue.push("Maya");
console.log(queue);
// [ 'Erin', 'Jordan', 'Maya' ]
.pop() removes the last item and returns it.
const queue = ["Erin", "Jordan", "Maya"];
const removed = queue.pop();
console.log(removed);
// Maya
console.log(queue);
// [ 'Erin', 'Jordan' ]
Checking for a Value: .includes() and .indexOf()
.includes() returns true or false depending on whether a value is in the array.
const stock = ["apple", "banana", "cherry"];
console.log(stock.includes("banana"));
// true
console.log(stock.includes("mango"));
// false
.indexOf() returns the index of a value, or -1 if it isn’t found.
const stock = ["apple", "banana", "cherry"];
console.log(stock.indexOf("cherry"));
// 2
console.log(stock.indexOf("mango"));
// -1
Use .includes() when you only care whether something is present. Use .indexOf() when you need to know where.
Copying a Slice: .slice()
.slice(start, end) returns a new array containing the items from start up to, but not including, end. It does not change the original array.
const nums = [10, 20, 30, 40, 50];
const middle = nums.slice(1, 3);
console.log(middle);
// [ 20, 30 ]
console.log(nums);
// [ 10, 20, 30, 40, 50 ]
Leaving off end slices to the end of the array.
const nums = [10, 20, 30, 40, 50];
console.log(nums.slice(2));
// [ 30, 40, 50 ]
Array Methods That Take a Function
In Module 4 you learned what a higher-order function is: a function that takes another function as an argument (or returns one). .map(), .filter(), and .reduce() are that exact pattern, applied to arrays. Each one takes a callback function and calls it once for every item in the array, the same way the custom higher-order functions you wrote in Module 4 called their callbacks. Nothing new to learn about the pattern itself here, just three built-in higher-order functions that save you from writing loops by hand.
.map(): Transform Every Item
.map() calls your callback once per item and builds a new array out of the return values. The new array is always the same length as the original.
const nums = [1, 2, 3];
const doubled = nums.map((n) => n * 2);
console.log(doubled);
// [ 2, 4, 6 ]
console.log(nums);
// [ 1, 2, 3 ]
The original array is untouched. .map() always produces a new one.
.filter(): Keep Some Items
.filter() calls your callback once per item and keeps only the items where the callback returns true. The result can be shorter than the original array.
const ages = [12, 17, 20, 25, 15];
const adults = ages.filter((age) => age >= 18);
console.log(adults);
// [ 20, 25 ]
.find(): Get the First Match
.filter() returns every item that matches. Sometimes you only want one, the first one. .find() calls your callback once per item and returns the first item where it returns true, or undefined if nothing matches.
const users = [
{ name: "Erin", age: 17 },
{ name: "Jordan", age: 25 },
{ name: "Maya", age: 30 }
];
const firstAdult = users.find((user) => user.age >= 18);
console.log(firstAdult);
// { name: 'Jordan', age: 25 }
const firstCentenarian = users.find((user) => user.age >= 100);
console.log(firstCentenarian);
// undefined
Notice .find() returns the item itself ({ name: 'Jordan', age: 25 }), not its index and not an array. If you need the index instead, that’s a different method, .findIndex(), not covered here.
.reduce(): Combine Everything Into One Value
.reduce() is the one that trips up most beginners, so slow down here. It walks through the array and builds up a single result, called the accumulator, by running your callback once per item.
const scores = [4, 8, 15];
const total = scores.reduce((accumulator, current) => accumulator + current, 0);
console.log(total);
// 27
Two things to notice in that call:
- The callback takes two arguments:
accumulator(the running total so far) andcurrent(the item being processed). - The
0after the callback is the starting value for the accumulator.
Here’s what happens step by step, tracing the accumulator through each call:
| Step | accumulator (before) | current | accumulator (after) |
|---|---|---|---|
| start | - | - | 0 (the starting value) |
| 1 | 0 |
4 |
0 + 4 = 4 |
| 2 | 4 |
8 |
4 + 8 = 12 |
| 3 | 12 |
15 |
12 + 15 = 27 |
After the last item, .reduce() returns the final accumulator value: 27. That’s the whole pattern: start with a value, update it once per item, return what’s left at the end.
.reduce() isn’t limited to sums. Here it is finding the largest number in an array, following the same shape:
const scores = [4, 8, 15];
const highest = scores.reduce((max, current) => {
if (current > max) {
return current;
}
return max;
}, scores[0]);
console.log(highest);
// 15
This time the accumulator (max) holds the highest value seen so far instead of a running total, and the starting value is the first item instead of 0. Same tool, different job.
Try It
- Create an array called
colorswith three strings. Log the item at index1and the array’s.length. - Starting from
["Erin", "Jordan"],.push()"Maya"onto it, then.pop()an item off. Log the array after each step. - Given
const team = ["Priya", "Sam", "Jordan Reyes"], use.includes()to check for"Sam"and.indexOf()to find"Jordan Reyes". - Given
const nums = [1, 2, 3, 4, 5], use.slice()to get just[2, 3, 4]. - Given
const prices = [20, 35, 50], use.map()to create a new array with 10% added to each price. - Given
const words = ["hi", "hello", "hey", "greetings"], use.filter()to keep only words with more than 3 letters. - Given
const nums = [10, 25, 40, 55], use.find()to get the first number greater than30. - Given
const nums = [3, 6, 9, 12], use.reduce()to sum them, then trace the accumulator by hand on paper before running the code.
Recap
- Arrays store ordered lists. Access items by index, starting at
0. .lengthtells you how many items are in the array..push()adds to the end,.pop()removes from the end..includes()checks whether a value exists,.indexOf()finds where..slice()copies out part of an array without changing the original..map(),.filter(),.find(), and.reduce()are higher-order functions, just like the ones you wrote in Module 4, applied to arrays:.map()transforms every item,.filter()keeps some items,.find()returns the first matching item (orundefined), and.reduce()combines everything into one value.
Next lesson: objects, for storing labeled data instead of ordered lists.