In JavaScript, arrays—denoted by the [] square brackets—are how we store lists of data. For example, say we want to build a shopping cart feature, we'd rely on an array to help us store the items in our shopping cart.

Arrays in JavaScript can contain any of the following value types:

  • Strings
  • Numbers
  • Objects
  • (Nested) Arrays
  • Functions

...and several others that are less common. In this tutorial, we're going to look at how to define an array, access the values of that array, and modify that array.

Defining an array

Defining an array is easy! Remember, all we need are the [] square brackets. For our example, we'll create a new array and assign it to a variable const shoppingCart:

const shoppingCart = [];

Simple enough? This is a bit boring, though. Let's add some items to our shopping cart in the form of JavaScript objects:

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

Here, each object in our array represents one item in our cart. For each item, we give it a unique id, a name, a price (per item), and a quantity of how many we want.

Although we're looking at a very particular version of an array (an "array of objects"), you can put other types of data—even mixing and matching—in an array, too:

const listOfNumbers = [1, 2, 3, 4, 5];
const listOfStrings = ['John', 'Paul', 'Ringo', 'George'];
const listOfArrays = [[1, 2, 3, 4, 5], ['John', 'Paul', 'Ringo', 'George']];

For the rest of this tutorial, we'll stick with our shopping cart example. Next up, let's take a look at how to access the values or contents of our array.

Accessing the values of an array

There are a lot of different ways to access the values of an array. Here, we're going to look at some of the more common methods that you're like to come across as you learn JavaScript.

Using the array index

The simplest way to retrieve a value from an array is to use the index of the item in an array. For example, let's take a look at our shoppingCart again:

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

Here, the index refers to the position of an item in the array. If we asked "what is the index of the object representing apples?" you might say "one?" This is wrong. Arrays in JavaScript are zero-based, meaning the first item is always referenced as 0.

So, in this example, if we wanted to get to the "Apples" item in our cart, we could write:

const apples = shoppingCart[0];
console.log(apples); // Logs { id: 1, name: 'Apples', price: 5.00, quantity: 4 }

Here, because we know that our array is stored in a variable shoppingCart, we can access its values using [] bracket notation. This is different from objects. Where objects can use . dot notation as well, arrays can only use [] bracket notation.

Here, we write shoppingCart[0] to say "give me the item at position zero in the array stored in the shoppingCart variable." Cool, right?!

While this is great if we know where an item is, more of than not, we won't know that an item exists. This is where some of our other means for accessing array values come in.

Using the .indexOf() method.

One of the more common methods for figuring out if an array contains a value is Array.indexOf(). This method is designed to answer "what is the index of some item in the array?" While helpful, .indexOf() is limited to finding the index of top-level values only (in other words, we can't find the index of one of our shopping cart items using its id).

const numbers = [1, 2, 3, 4, 5];

For example, in this simple array of numbers, if we write the following:

const indexOfFour = numbers.indexOf(4);
console.log(indexOfFour); // Logs 3.

Wait! What?! Yep. Remember that array indexes are zero-based. So, in this case, if our first number 1 is position zero, if we count up we get "zero, one, two, three." Keep this in mind whenever you're working with arrays. It's one of the most common logical gotchas that can trip beginners up.

One trick that you may see .indexOf() being used for is to verify that a value exists, like this:

if (numbers.indexOf(4) > -1) {
  console.log('4 exists!');
}

Why > -1? This is because if indexOf() cannot find an index for a value, it will return a -1. We use > -1 greater than here because...we might get a zero back for our index!

Again, .indexOf() is limited as a means for "finding" something in an array. It can only "search" based on top-level values, not nested values. We'll look at a means for a more intelligent search below.

Using the .includes() method.

A more friendly version of the .indexOf() method of searching is the Array.includes() method. Similar to .indexOf(), it's limited to top-level values only. What makes .includes() different is that it doesn't return an index or a value: it only tells us if that value exists in the array.

const listOfStrings = ['John', 'Paul', 'Ringo', 'George'];

Here, considering our array of strings, we can find out if a specific string exists:

console.log(listOfStrings.includes('Ringo')); // Logs true
console.log(listOfStrings.includes('ringo')); // Logs false

Notice that .includes() is very specific. Here, even though we're specifying the same name for each example, because the value in the array is capitalized, .includes() will only match on listOfStrings.includes('Ringo') but not the lowercase variant.

Pro tip: rely heavily on lowercased values (ringo), dashed values (ringo-starr), or snake-cased values (ringo_starr). Doing this makes searching and finding values in JavaScript far easier than when you're using mixed casing.

Again, .includes() is very limited. If we want to do a more specific find, we need to use the JavaScript .find() method.

Using the .find() method.

The .find() method is one of the more appropriately named array methods. It helps us to find the first value matching the criteria of a function that we pass to it. Again, bringing back our shoppingCart example:

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

Here, let's say we want to find the item in our cart representing "Coffee Beans." With a .find() we can do...

const coffeeBeans = shoppingCart.find((item) => {
  return item.name === 'Coffee Beans';
});
console.log(coffeeBeans); // Logs { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 }

Notice that here, instead of just passing some value to .find() like .find('Coffee Beans'), instead, we pass a function that's called for each item in the array until we find a match. To make sure that's clear, here's another example:

const expensiveItem = shoppingCart.find((item) => {
  return item.price > 5;
});
console.log(expensiveItem); // Logs { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 }

Here, we try to find an item that costs more than 5 dollars. In our example cart, our "Protein Bars" item costs 10.00 (the only item above 5) and so we get that back as our expensiveItem. Neat, yeah?

The .find() method is incredibly powerful. Remember: it will only return the first match, not multiple items.

Looping (or iterating) over an array

When most people think about arrays, it's likely that the "loop" is what comes to mind. Loops are a way to iterate over an array. So, given an array like this:

const numbers = [1, 2, 3, 4, 5];

A loop would evaluate each item in the array, in order, separately. If we were to demonstrate this verbally, I'd ask "what are the numbers in the numbers array?" You'd respond "one, two, three, four, and five." You saying that was a loop! You "looped over" the array by looking at each number in the array and saying the value.

Using the `.forEach()` method

One of the most common forms of looping in JavaScript is the .forEach() method. This method allows us to iterate over an array and do something for each item in the array.

const numbers = [1, 2, 3, 4, 5];

numbers.forEach((number, index) => {
  console.log(`The number at index ${index} is:`, number);
});

Here, we use .forEach() to iterate over the numbers array. For each item, we want to log out a string that tells us the index of the number in the array as well as the number itself. Notice that the .forEach() method receives the current number or value it's looping over as its first argument and the index of that value as its second argument.

In this example, we'd see the following logged out to our console:

The number at index 0 is: 1
The number at index 1 is: 2
The number at index 2 is: 3
The number at index 3 is: 4
The number at index 4 is: 5

You can do anything you want inside of a loop. Here, a console.log() pretty simple, but we could go even further:

let total = 0;

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

shoppingCart.forEach((item) => {
  total += (item.price * item.quantity);
});

console.log(total); // Logs 37.98

Here, we use a .forEach() to say "for each item in our shopping cart, add the item.price multiplied by the item.quantity and add it to the total variable." Here, the += operator is saying "take the current value of total and add the result of the right-hand side to it."

In this case, for each iteration of our loop, the total is being assigned the total for that item. The reason our total gets to 37.98 is that we're doing this math for each item in our array until we get to the end. This means that .forEach() is synchronous or blocking. In other words, our console.log(total) will not be evaluated by JavaScript until every item in the array has been looped over with our .forEach().

Using the for loop.

The for loop is another common variation of looping over items, it's relatively similar to .forEach() but has a slightly different syntax.

let total = 0;

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

for(let item = 0; item < shoppingCart.length; item += 1) {
  total += (shoppingCart[item].price * shoppingCart[item].quantity);
}

console.log(total); // Logs 37.98

Same result, different means of getting there. Here, notice that a for loop involves a few more moving parts. First, to define the loop we initialize the starting index (literally, from what index do we want to start) with let item = 0; or "start from the beginning." Next, we say that "we want to run our loop as long as the index stored in item is less than the length of our shoppingCart array. Finally, we say "for each iteration of the loop, increment our index item by 1."

Woof! That's a lot. Notice, too, that inside of the body of our loop (everything between the {}) we do something similar to our .forEach(), however, how we access each item has changed. Instead of getting a variable passed to our function for each item, we have to access the value ourselves.

Here, item represents only the index of the item, not the actual item itself. So, we need to use the bracket notation we learned earlier to say shoppingCart[item] where item will be 0, 1, 2, or 3. In response to shoppingCart[item], then, we get back the item at the corresponding index.

For example, when the current index being looped over is 2, we'd expect to be evaluating the "Carton of Eggs."

Using the while loop.

While loops are similar to for loops, however, serve a different purpose. Like the name suggests, while loops are loops that run as long as some condition is met.

let currentItem = 0;
let total = 0;

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

while(currentItem < shoppingCart.length) {
  total += (shoppingCart[currentItem].price * shoppingCart[currentItem].quantity);
  currentItem += 1;
}

console.log(total); // Logs 37.98

Same exact result, different means. Here, we've added a new variable currentItem that we use to tell us the current position or index in the array. This is identical to the item variable that we created as part of our for loop example above.

The difference, here, is that a while loop does not give us the ability to specify that value directly, nor does it give us the ability to specify how that value should change on each iteration. Instead, managing both of those things is left up to us.

Here, notice that the body {} of our while loop uses a similar syntax to the for loop by referencing the current index as currentItem and then gets the value in the array at that index shoppingCart[currentItem]. Though we've changed the name of the variable from item to currentItem, the behavior here is identical to what we saw above.

Which one should I use?

Though it may be frustrating, which version of the loop to use depends on the work you're trying to do. As we'll see below, there are other types of loops that are designed specifically for the work we did above but using less code.

When you're just getting started, it's best to use the .forEach() loop if you just want to loop over an array without modifying the items.

Modifying an array

If you want to modify an array, I have some good news: JavaScript has a ton of methods (the name we use for functions defined on the Array prototype, or, the definition of what an array is and what it can do in JavaScript). Now, we're going to take a look at some of the more common methods for modifying an array. This isn't everything but these are definitely the methods you'll see most often and the ones that will make you the most productive.

Using the .push() method.

The simplest way to modify an array in JavaScript is to add something to it. To add something to an array, we can use the .push() method:

const numbers = [1, 2, 3, 4, 5];

numbers.push(6);

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

Very simple. Here, we say "take our numbers array and 'push' the number 6 into that array." When we do this, we modify the array in memory. This means that the original array is changed after numbers.push(6) is called, which is why we see 6 in the array when we console.log(numbers).

Just like we can define an array with any of the values we listed at the start of this tutorial, we can also .push() any of those values into an array. Just be careful not to push something into an array that your code doesn't know how to handle (for example, adding a string to an array of numbers and having code that expects the array to contain only numbers).

Using the .map() method.

The .map() method is another means for modifying an array, but with the purpose of modifying what already exists (not adding or removing from it).

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

const shoppingCartWithTaxIncluded = shoppingCart.map((item) => {
  return {
      ...item,
      price: item.price + (item.price * 0.05),
  };
});

Because we're running a totally legit grocery store and don't want to piss off the man, it's probably wise to collect taxes on each of our items. Here, we use the .map() method to help us say "loop over the shoppingCart array, but for each item, we want to return the item but set the price to be the item's price + the item's price * 0.05 (5% tax)."

Wait! What's that ...item thing? This is the "spread operator" which is used to "spread out" or unpack the contents of one object onto another. Take a look at this tutorial on objects to learn more.

In response to the .map() method, we get back a new copy of the array with each item's price updated to include the new 5% tax. Notice that we store the response of the .map() in a new variable called shoppingCartWithTaxIncluded.

Using the .filter() method.

The .filter() method is similar to .map() in that it takes an existing array and returns us a new one. Like the name implies, though, what's different about it is that it's designed to filter out stuff that we don't want.

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

const inexpensiveItems = shoppingCart.filter((item) => {
  return item.price < 5;
});

Here, we use a filter function to say "loop over all of the items in the shoppingCart array and only return the items in the array that have a price less than 5." Just like we saw with the .map(), we get back our new array and store it in a new variable inexpensiveItems.

Using the .reduce() method.

Next up is the .reduce() method. Like we hinted at earlier, the .reduce() method is a nice way to say "given some starting point or value, loop over the array and for each item in the array, modify the starting value as you go."

If you're following along, that sounds like what we need to do to total up our items!

const shoppingCart = [
  { id: 1, name: 'Apples', price: 5.00, quantity: 4 },
  { id: 2, name: 'Protein Bars', price: 10.00, quantity: 1 },
  { id: 3, name: 'Carton of Eggs', price: 2.99, quantity: 1 },
  { id: 4, name: 'Coffee Beans', price: 4.99, quantity: 1 },
];

const total = shoppingCart.reduce((runningTotal, item) => {
  return runningTotal += (item.price * item.quantity);
}, 0);

This one's a little bit different. Notice that we use a similar function syntax to the other methods, but we've added a few things. First, notice that .reduce() takes two arguments: a function to perform our work and a staring value. That starting value, or 0 here, is then passed as the runningTotal argument to the function we passed to .reduce().

The idea here is that, starting from 0, for each item in our array, we want to modify that 0. So, on the first iteration of our shoppingCart, using the += operator we do the math 0 + 20.00. On our second loop, then, runningTotal is equal to 20.00 and so after we add our second item, runningTotal becomes 30.00.

This continues until we hit the end of our array. In response, we get back the final runningTotal, which is why we've assigned our call to shoppingCart.reduce() to a variable const total. Neat, right?

Using the .reverse() method.

Sometimes we need to loop over an array, but before we do, reverse its contents so we can loop over them in the opposite order:

const numbers = [1, 2, 3, 4, 5];

numbers.reverse().forEach((number) => {
  console.log('The current number is', number);
});

Here, we take the numbers array and add the .reverse() method on to the end of it before we chain on .forEach() on the end. The result here is what you might expect:

The current number is 5
The current number is 4
The current number is 3
The current number is 2
The current number is 1

Super handy!

Using the .sort() method.

The sort method is equally simple but also handy to have around. Like the name implies, the .sort() helps us to...sort an array! Keep in mind: the sorting here is very simple. For strings it will sort alphabetically and for numbers it will sort in order from lowest to highest.

const numbers = [8, 6, 7, 5, 3, 0, 9];

console.log(numbers.sort()); // Logs [0, 3, 5, 6, 7, 8, 9]

Simple but useful when you're in a pinch. Just to make sure this is clear, here's another example with strings:

const listOfStrings = ['John', 'Paul', 'Ringo', 'George'];

console.log(listOfStrings.sort());
// Logs ['George', 'John', 'Paul', 'Ringo']

Again, this is very simplistic. It can work with simple strings, numbers, and even dates! Always make sure to verify the output though instead of blindly trusting it.

Using the ... spread operator

One last tool you may see is the ... or "spread operator." Like we covered in our look at objects, when it comes to arrays the spread operator can help us to "copy" one arrays contents into another.

const luckyNumbers = [19, 113, 152];
const unluckyNumbers = [17, 93, 18, 22];
const lottery = [...luckyNumbers, ...unluckyNumbers];

console.log(lottery); // Logs [19, 113, 152, 17, 93, 18, 22]

Cool! Here, we're using the ... spread operator to say "we want to combine together the luckyNumbers with the unluckyNumbers." So, in this case, we create a new array using the [] square brackets and then inside, we write ...luckyNumbers to say "unpack the lucky numbers into the new array" and then ...unluckyNumbers to say "unpack the unlucky numbers into the new array."

The end result is that our new array contains both sets of numbers as one array! Notice that order matters here: the order in which you spread out a value is where it will appear in the array. So that's clear, if we reverse the above:

const luckyNumbers = [19, 113, 152];
const unluckyNumbers = [17, 93, 18, 22];
const lottery = [...unluckyNumbers, ...luckyNumbers];

console.log(lottery); // Logs [17, 93, 18, 22, 19, 113, 152]

We get the opposite result. Hot dog :)

A whole lot more

This should get you up to speed and productive with arrays. But keep in mind: what we just learned is only part of the story! There are a ton of array methods and techniques that you can use to access the values of, loop over, and modify an array. We've picked out the most common and most beginner-friendly ones here, but don't be afraid to go and explore a bit further!