Tutorials Books Videos Forums

Change the theme! Search!
Rambo ftw!

Customize Theme


Color

Background


Done

Table of Contents

Array and Object Destructuring in JavaScript

by kirupa   |   filed under JavaScript 101

A lot of the improvements made to JavaScript revolve around adding missing capabilities such as being able to access the webcam, using cool new data structures like Sets, interacting in more creative ways with the DOM, and more. Some improvements fall purely in the convenience side of the house. There are many highly inconvenient JavaScript tasks that we regularly perform that either take too much code or require too many "gotchas" to work properly. One such task involves taking values from arrays or objects and storing them in variables.Allow me to elaborate. Let's say that we have an array and it contains the following items:

let winners = ["bear", "cat", "dog", "giraffe", "unicorn"];

What we want to do is store the first three items from this array. The common approach that we would use is one that looks as follows:

let winners = ["bear", "cat", "dog", "giraffe", "unicorn"];

let firstPlace = winners[0];
let secondPlace = winners[1];
let thirdPlace = winners[2];

console.log(firstPlace); // bear
console.log(secondPlace); // cat

If we want to store every item in our array in its own variable or store the remaining items that aren't the first three values, this would require a lot more array manipulation techniques and/or copy and paste activities. Tasks such as this extend to objects as well where we may want to store certain properties into their own variables as shown below:

let returnedData = {
    "id": 54901,
    "name": Laserific Spoon 2000,
    "price": $5.00,
    "inStock": false,
    "inventor": Dr. Atom
};

let productID = returnedData.id;
let inventor = returnedData.inventor;

console.log(productID); // 54901
console.log(inventor); // Dr. Atom

As our web apps become more data intensive with us relying more and more on JavaScript to process this data, the traditional approaches for accessing data and storing them in variables becomes clunky. That is where the star of this chapter comes in, destructuring. Destructuring is all about making it easy to go from a chunk of data, stored either in an array or an object, and unpacking that data into variables. We'll look at what all of this entails in the following sections.

Onwards!

Destructuring Examples

The concepts behind destructuring are not very deep, so the best way to learn how it works is by just looking at a bunch of examples spanning across both arrays and objects.

General Overview using Arrays

Let's go back to the array example we started with earlier:

let winners = ["bear", "cat", "dog", "giraffe", "unicorn"];

If we want to store the first three items from the array in their own variables, here is how we can do that by using destructuring:

let winners = ["bear", "cat", "dog", "giraffe", "unicorn"];

let [firstPlace, secondPlace, thirdPlace] = winners;

console.log(firstPlace); // bear
console.log(secondPlace); // cat
console.log(thirdPlace); // dog

We use this bizarre array-like syntax as part of the variable declaration to define the three variables (firstPlace, secondPlace, thirdPlace) that will store the first three items from our winners array. One of the other activities we called out earlier is how we can store the remaining items from the array that aren't in the first, second, or third positions. Well...as it turns out, there is a special operator called the spread operator (...) that allows us to do that very easily:

let winners = ["bear", "cat", "dog", "giraffe", "unicorn"];

let [firstPlace, secondPlace, thirdPlace, ...others] = winners;

console.log(firstPlace); // bear
console.log(secondPlace); // cat
console.log(thirdPlace); // dog
console.log(others); // [giraffe, unicorn, dinosaur]

Notice that we have the ...others expression where we pair the spread operator (...)with a variable called others. The output is the remaining array values after firstPlace, secondPlace, and thirdPlace get mapped.

If we had to visualize all of this, we would see something similar to the following:

Really cool, right? Now, what we have seen is the elevator pitch for what destructuring looks like and the syntax we will rely on. What we will do next is go even deeper and look at more examples that touch upon the edge cases that we run into.

Skipping Items with a Comma

We sorta kinda see the importance that the comma plays in destructuring. Each variable is comma separated, and the comma helps indicate when we jump from one item in our array to the next in sequential order. This knowledge is handy if we want to skip an item from being assigned to a variable. To skip an item (or many items), we need to specify a comma but no variable to pair with the comma.

Take a look at the following example:

let [a, , b] = [1, 2, 3, 4, 5, 6, 7];

console.log(a); // 1
console.log(b); // 3

Notice that we specify an empty comma after the a variable. This ends up appearing as two commas, and the result is one where we map only the first item and the third item. The second item is skipped since there is no variable to store that item.

When There Are More Variables than Data

Sometimes we may be trying to map more variables than there is data to map to it. Take a look at the following example:

let [first, second, third] = ["Homer", "Marge"];

console.log(first); // "Homer"
console.log(second); // "Marge"
console.log(third); // undefined

The array we are trying to unpack into variables only has two items, but we have three variables. What happens is that when we have a variable that doesn't have any data associated with it, that variable is given a value of undefined. That is what we see happening when we inspect the value of our third variable.

If the undefined value is undesirable, we can specify a default value to override that behavior:

let [first, second, third = "Person"] = ["Homer", "Marge"];

console.log(first); // Homer
console.log(second); // Marge
console.log(third); // Person

In this variation, notice that the the value for third is set to the default value of Person because it doesn't have a defined value in the array.

Separating the Declaration and Assignment

Just like how we can separate the declaration and assignment activities when working with variables, we can do that same thing when destructuring. I will warn you though. It is going to look a little strange at first, but it is totally legit:

let foo;
let bar;

[foo, bar] = [1, 2];

console.log(foo) // 1
console.log(bar) // 2

Notice that we declare our foo and bar variables first, and we then assign those variables later when we destructure the contents of our array.

Destructuring with Objects

In past few sections, we saw how destructuring works with arrays. Destructuring also works with objects, and a lot of what we saw earlier applies fully in this objectified world. Take a look at the following object:

let chair = {
  brand: "Le Chair",
  legs: "4",
  material: "Wood",
  inventory: "42",
  price: "$29.99",
  color: "Blue"
};

We have an object called chair, and it contains a bunch of properties. If we want to extract and store the values of just the brand and price properties, we can do so via destructuring:

let chair = {
  brand: "Le Chair",
  legs: "4",
  material: "Wood",
  inventory: "42",
  price: "$29.99",
  color: "Blue"
};

let {brand, price} = chair;

console.log(brand); // "Le Chair"
console.log(price); // "$29.99"

In our variable declaration and assignment, we are declaring two variables called brand and price whose name matches the property names inside the object we are unpacking. The end result is we are able to work with the values stored by brand and price properties as their own individual variables.

As we can see, our chair object contains more properties than just brand and price. If we wanted to access the remaining properties without any manual bookkeeping, the spread operator exists in this context as well:

let chair = {
  brand: "Le Chair",
  legs: "4",
  material: "Wood",
  inventory: "42",
  price: "$29.99",
  color: "Blue"
}

let {brand, price, ...rest} = chair;

console.log(brand); // "Le Chair"
console.log(price); // "$29.99"
console.log(rest); /* { 
                      legs: '4', 
                      material: 'Wood', 
                      inventory: '42', 
                      color: 'Blue'
                     } */

The rest variable stores the results of destructuring our object using the spread operator. What gets returned is a new object whose properties are the ones we haven't unpacked. In other words, this new object contains everything except the brand and price properties. Really cool, right?

Destructuring Differences Between Arrays and Objects

In this happy world of destructuring, what differentiates what we see here with objects from what we saw with arrays previously are three big things:

  1. The destructuring assignment for arrays involves brackets let [a, b] = [1, 2]. The destructuring assignment for objects involves curly braces: let {a, b} = { a: 1, b: 2 }.
  2. With arrays, the order of our variable names during assignment mapped to the order of our items in the array. With objects, order doesn't matter. The variable names determine which of our object property values get mapped.
  3. With arrays, the spread operator returns a new array whose contents are a consecutive list of array values starting right after the ones we had already mapped. With objects, the spread operator returns a new object made up of the properties we haven't already mapped. The order of how the properties are defined inside the object doesn't matter. The only thing that matters is which properties have already been mapped and which ones haven't.

There are a handful of other subtle differences, but these are the big ones.

Assigning to New Variable Names

In our earlier snippets, the variable names mapped to the property names we are accessing inside the object. That is the default behavior, but we may often want different variable names that are decoupled from the internals of an object's property naming. Fortunately, we have a way of doing that. Take a look at the following example:

let chair = {
  brand: "Le Chair",
  legs: "4",
  material: "Wood",
  inventory: "42",
  price: "$29.99",
  color: "Blue"
};

let {brand, price: cost} = chair;

console.log(brand); // "Le Chair"
console.log(cost); // "$29.99"

Pay attention to our destructuring assignment. Notice that we have the price property mapping to the value in the chair object we are trying to access BUT we remapped the variable name to be cost instead. We did by using a colon character between the variable that maps to the object property name and the name we specify as the new variable name. The end result of this snippet is that we can use the cost variable to to access the value of the price property instead of using the price name.

Note: There's are More Cases!

As with anything as general purpose as destructuring, there are many more cases covering uncommon (yet very important) scenarios than what we have covered here. For a full list of all the destructuring shenanigans that one can see with arrays and objects, the MDN documentation on this topic is perfect: https://mzl.la/3I2Lbre

Conclusion

Destructuring is one of those topics that has the potential to greatly simplify how we map variables to data stored inside our arrays and objects. It is important for us to understand the slightly bizarre-looking syntax made up of brackets, curly braces, and periods. Even if you and I have no plans of ever using this in our code, destructuring has gotten so common (especially in frameworks like React and Vue), that we'll find ourselves forced to use it or review/read code written by someone else that heavily relies on it.

Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!

Kirupa's signature!

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends

:: Copyright KIRUPA 2024 //--