Introduction
If you wanted to select elements from an array or object before the ES2015 update to JavaScript, you would have to individually select them or use a loop.
The ES2015 specification introduced the destructuring assignment, a quicker way to retrieve array elements or object properties into variables.
In this article, we'll use the destructuring assignment to get values from arrays and objects into variables. We'll then see some advanced usage of the destructuring assignment that allows us to set default values for variables, capture unassigned entries, and swap variables in one line.
Array Destructuring
When we want to take items from an array and use them in separate variables, we usually write code like this:
let myArray = [1, 2, 3];
let first = myArray[0];
let second = myArray[1];
let third = myArray[2];
Since the major ES2015 update to JavaScript, we can now do that same task like this:
let myArray = [1, 2, 3];
let [first, second, third] = myArray;
The second, shorter example used JavaScript's destructuring syntax on myArray
. When we destructure an array, we are copying the values of its elements to variables. Array destructuring syntax is just like regular variable assignment syntax (let x = y;
). The difference is that the left side consists of one or more variables in an array.
The above code created three new variables: first
, second
, and third
. It also assigned values to those variables: first
is equal to 1, second
is equal to 2, and third
is equal to 3.
With this syntax, JavaScript sees that first
and 1 have the same index in their respective arrays, 0. The variables are assigned values corresponding to their order. As long as the location matches between the left and right side, the destructuring assignment will be done accordingly.
The destructuring syntax also works with objects, let's see how.
Object Destructuring
Before the destructuring syntax was available, if we wanted to store an object's properties into different variables we would write code like this:
const foobar = {
foo: "hello",
bar: "world"
};
const foo = foobar.foo;
const bar = foobar.bar;
With the destructuring syntax, we can now quickly do the same thing with fewer lines of code:
const foobar = {
foo: "hello",
bar: "world"
};
const { foo, bar } = foobar;
While array items are destructured via their position, object properties are destructured by their key name. In the above example, after declaring the object foobar
we then create two variables: foo
and bar
. Each variable is assigned the value of the object property with the same name. Therefore foo
is "hello" and bar
is "world".
Note: The destructuring assignment works whether you declare a variable with var
, let
, or const
.
If you prefer to give a different variable name while destructuring an object, we can make a minor adjustment to our code:
const foobar = {
foo: "hello",
bar: "world"
};
const { foo: baz, bar } = foobar;
console.log(baz, bar); // hello world
With a colon, we can match an object property and give the created variable a new name. The above code does not create a variable foo
. If you try to use foo
you will get a ReferenceError
, indicating that it was not defined.
Now that we've got the basics of destructuring arrays and objects, let's look at some neat tricks with this new syntax. We'll start with our option to select default values.
Default Values in Destructured Variables
What happens if we try to destructure more variables than the number of array elements or object properties? Let's see with a quick example:
let [alpha1, alpha2, alpha3] = ['a', 'b'];
console.log(alpha1, alpha2, alpha3);
Our output will be:
a b undefined
Unassigned variables are set to undefined
. If we want to avoid our destructured variables from being undefined
, we can give them a default value. Let's reuse the previous example, and default alpha3
to 'c':
let [alpha1, alpha2, alpha3 = 'c'] = ['a', 'b'];
console.log(alpha1, alpha2, alpha3);
If we run this in node
or the browser, we will see the following output in the console:
a b c
Default values are created by using the =
operator when we create a variable. When we create variables with a default value, if there's a match in the destructuring environment it will be overwritten.
Let's confirm that's the case with the following example, which sets a default value on an object:
const { prime1 = 1, prime2 } = { prime1: 2, prime2: 3 };
console.log(prime1, prime2);
In the above example, we default prime1
to 1. It should be overwritten to be 2 as there is a prime1
property on the object in the right-hand side of the assignment. Running this produces:
2 3
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
Great! We've confirmed that default values are overwritten when there's a match. This is also good because the first prime number is indeed 2 and not 1.
Default values are helpful when we have too little values in the array or object. Let's see how to handle cases when there are a lot more values that don't need to be variables.
Capturing Unassigned Entries in a Destructured Assignment
Sometimes we want to select a few entries from an array or object and capture the remaining values we did not put into individual variables. We can do just that with the ...
operator.
Let's place the first element of an array into a new variable, but keep the other elements in a new array:
const [favoriteSnack, ...fruits] = ['chocolate', 'apple', 'banana', 'mango'];
In the above code, we set favoriteSnack
to 'chocolate'. Because we used the ...
operator, fruits
is equal to the remaining array items, which is ['apple', 'banana', 'mango']
.
We refer to variables created with ...
in the destructuring assignment as the rest element. The rest element must be the last element of the destructuring assignment.
As you may have suspected, we can use the rest element in objects as well:
const { id, ...person } = {
name: 'Tracy',
age: 24,
id: 1020212,
};
We extract the id
property of the object on the right-hand side of the destructuring assignment into its own variable. We then put the remaining properties of the object into a person
variable. In this case, id
would be equal to 1020212
and person
would be equal to { name: 'Tracy', age: 24 }
.
Now that we've seen how to keep all the data, let's see how flexible the destructuring assignment is when we want to omit data.
Selective Values in a Destructuring Assignment
We don't have to assign every entry to a variable. For instance, if we only want to assign one variable from many options we can write:
const [name] = ['Katrin', 'Judy', 'Eva'];
const { nyc: city } = { nyc: 'New York City', ldn: 'London' };
We assigned name
to 'Katrin' from the array and city
to 'New York City' from the object. With objects, because we match by key names it's trivial to select particular properties we want in variables. In the above example, how could we capture 'Katrin' and 'Eva' without having to take 'Judy' as well?
The destructuring syntax allows us to put holes for values we aren't interested in. Let's use a hole to capture 'Katrin' and 'Eva' in one go:
const [name1, , name2] = ['Katrin', 'Judy', 'Eva'];
Note the gap in the variable assignment between name1
and name2
.
So far we have seen how flexible the destructuring assignment can be, albeit only with flat values. In JavaScript, arrays can contain arrays and objects can be nested with objects. We can also have arrays with objects and objects with arrays. Let's see how the destructuring assignment handles nested values.
Destructuring Nested Values
We can nest destructuring variables to match nested entries of an array and object, giving us fine-grained control of what we select. Consider having an array of arrays. Let's copy the first element of each inner array into their own variable:
let [[part1], [part2], [part3], [part4]] = [['fee', 'mee'], ['fi', 'li'], ['fo', 'ko'], ['fum', 'plum']];
console.log(part1, part2, part3, part4);
Running this code will display the following output:
fee fi fo fum
By simply wrapping each variable in the left-hand side with []
, JavaScript knows that we want the value within an array and not the array itself.
When we destructure nested objects, we have to match the key of the nested object to retrieve it. For example, let's try to capture some details of a prisoner in JavaScript:
const {
name,
crimes: {
yearsToServe
}
} = {
name: 'John Doe',
crimes: {
charged: ['grand theft auto', 'stealing candy from a baby'],
yearsToServe: 25
}
};
console.log(yearsToServe);
To get the yearsToServe
property, we first need to match the nested crimes
object. In this case, the right-hand side has a yearsToServe
property of the crimes
object set to 25. Therefore, our yearsToServe
variable will be assigned a value of 25.
Note that we did not create a crimes
object in the above example. We created two variables: name
and yearsToServe
. Even though we must match the nested structure, JavaScript does not create intermediate objects.
You've done great so far in covering a lot of the destructured syntax capabilities. Let's have a look at some practical uses for it!
Use Cases for Destructuring Arrays and Objects
There are many uses for destructuring arrays and object, in addition to the lines of code benefits. Here are a couple of common cases where destructuring improves the readability of our code:
For Loops
Developers use the destructuring assignment to quickly pull values of interest from an item in a for
loop. For example, if you wanted to print all the keys and values of an object, you can write the following:
const greetings = { en: 'hi', es: 'hola', fr: 'bonjour' };
for (const [key, value] of Object.entries(greetings)) {
console.log(`${key}: ${value}`);
}
First, we create a greetings
variable that stores how to say "hello" in different languages. Then we loop through the values of the object using the Object.entries()
method which creates a nested array. Each object property is represented by 2 dimensional array with the first item being the key and the second item being its value. In this case, Object.entries()
creates the following array [['en', 'hi'], ['es', 'hola'], ['fr', 'bonjour']]
.
In our for
loop, we destructure the individual arrays into key
and value
variables. We then log them to the console. Executing this program gives the following output:
en: hi
es: hola
fr: bonjour
Swapping Variables
We can use the destructuring syntax to swap variables without a temporary variable. Let's say you're at work and taking a break. You wanted some tea, while your coworker wanted some coffee. Unfortunately, the drinks got mixed up. If this were in JavaScript, you can easily swap the drinks using the destructuring syntax:
let myCup = 'coffee';
let coworkerCup = 'tea';
[myCup, coworkerCup] = [coworkerCup, myCup];
Now myCup
has 'tea' and coworkerCup
has 'coffee'. Note how we did not have let
, const
, or var
when using the destructuring assignment. As we aren't declaring new variables, we need to omit those keywords.
Conclusion
With the destructuring assignment, we can quickly extract values from arrays or objects and put them into their own variables. JavaScript does this by matching the variable's array position, or the name of the variable with the name of the object property.
We've seen that we can assign default values to variables we are creating. We can also capture the remaining properties of arrays and objects using the ...
operator. We can skip entries by having holes, which are indicated by commas with nothing in between them. This syntax is also flexible enough to destructure nested arrays and objects.
We provided a couple of nifty places to use the destructuring assignment. Where will you use them next?