Destructing
The two most used data structures in JavaScript are Object
and Array
.
Objects allow us to create a single entity that stores data items by key.
Arrays allow us to gather data items into an ordered list.
However, when we pass these to a function, we may not need all of it. The function might only require certain elements or properties.
Destructuring assignment is a special syntax that allows us to “unpack” arrays or objects into a bunch of variables, as sometimes that’s more convenient.
Destructuring also works well with complex functions that have a lot of parameters, default values, and so on. Soon we’ll see that.
Array destructuring
Here’s an example of how an array is destructured into variables:
Now we can work with variables instead of array members.
It looks great when combined with split
or other array-returning methods:
As you can see, the syntax is simple. There are several peculiar details though. Let’s see more examples to understand it better.
“Destructuring” does not mean “destructive”.
It’s called “destructuring assignment,” because it “destructurizes” by copying items into variables. However, the array itself is not modified.
It’s just a shorter way to write:
Ignore elements using commas
Unwanted elements of the array can also be thrown away via an extra comma:
In the code above, the second element of the array is skipped, the third one is assigned to title
, and the rest of the array items are also skipped (as there are no variables for them).
Works with any iterable on the right-side
…Actually, we can use it with any iterable, not only arrays:
That works, because internally a destructuring assignment works by iterating over the right value. It’s a kind of syntax sugar for calling for..of
over the value to the right of =
and assigning the values.
Assign to anything at the left-side
We can use any “assignables” on the left side.
For instance, an object property:
Looping with .entries()
In the previous chapter, we saw the Object.entries(obj) method.
We can use it with destructuring to loop over the keys-and-values of an object:
The similar code for a Map
is simpler, as it’s iterable:
Swap variables trick
There’s a well-known trick for swapping values of two variables using a destructuring assignment:
Here we create a temporary array of two variables and immediately destructure it in swapped order.
We can swap more than two variables this way.
The rest ‘…’
Usually, if the array is longer than the list at the left, the “extra” items are omitted.
For example, here only two items are taken, and the rest is just ignored:
If we’d like also to gather all that follows – we can add one more parameter that gets “the rest” using three dots "..."
:
The value of rest
is the array of the remaining array elements.
We can use any other variable name in place of rest
, just make sure it has three dots before it and goes last in the destructuring assignment.
Default values
If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined:
If we want a “default” value to replace the missing one, we can provide it using =
:
Default values can be more complex expressions or even function calls. They are evaluated only if the value is not provided.
For instance, here we use the prompt
function for two defaults:
Please note: the prompt
will run only for the missing value (surname
).
Object destructuring
The destructuring assignment also works with objects.
The basic syntax is:
We should have an existing object on the right side, that we want to split into variables. The left side contains an object-like “pattern” for corresponding properties. In the simplest case, that’s a list of variable names in {...}
.
For instance:
Properties options.title
, options.width
and options.height
are assigned to the corresponding variables.
The order does not matter. This works too:
The pattern on the left side may be more complex and specify the mapping between properties and variables.
If we want to assign a property to a variable with another name, for instance, make options.width
go into the variable named w
, then we can set the variable name using a colon:
The colon shows “what : goes where”. In the example above the property width
goes to w
, property height
goes to h
, and title
is assigned to the same name.
For potentially missing properties we can set default values using "="
, like this:
Just like with arrays or function parameters, default values can be any expressions or even function calls. They will be evaluated if the value is not provided.
In the code below prompt
asks for width
, but not for title
:
We also can combine both the colon and equality:
If we have a complex object with many properties, we can extract only what we need:
The rest pattern “…”
What if the object has more properties than we have variables? Can we take some and then assign the “rest” somewhere?
We can use the rest pattern, just like we did with arrays. It’s not supported by some older browsers (IE, use Babel to polyfill it), but works in modern ones.
It looks like this:
Gotcha if there’s no let
let
In the examples above variables were declared right in the assignment: let {…} = {…}
. Of course, we could use existing variables too, without let
. But there’s a catch.
This won’t work:
The problem is that JavaScript treats {...}
in the main code flow (not inside another expression) as a code block. Such code blocks can be used to group statements, like this:
So here JavaScript assumes that we have a code block, that’s why there’s an error. We want destructuring instead.
To show JavaScript that it’s not a code block, we can wrap the expression in parentheses (...)
:
Nested destructuring
If an object or an array contains other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions.
In the code below options
has another object in the property size
and an array in the property items
. The pattern on the left side of the assignment has the same structure to extract values from them:
All properties of options
object except extra
that is absent in the left part, are assigned to corresponding variables:
Finally, we have width
, height
, item1
, item2
and title
from the default value.
Note that there are no variables for size
and items
, as we take their content instead.
Smart function parameters
There are times when a function has many parameters, most of which are optional. That’s especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on.
Here’s a bad way to write such a function:
In real-life, the problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still… Another problem is how to call a function when most parameters are ok by default.
Like this?
That’s ugly. And becomes unreadable when we deal with more parameters.
Destructuring comes to the rescue!
We can pass parameters as an object, and the function immediately destructurizes them into variables:
We can also use more complex destructuring with nested objects and colon mappings:
The full syntax is the same as for a destructuring assignment:
Then, for an object of parameters, there will be a variable varName
for property incomingProperty
, with defaultValue
by default.
Please note that such destructuring assumes that showMenu()
does have an argument. If we want all values by default, then we should specify an empty object:
We can fix this by making {}
the default value for the whole object of parameters:
In the code above, the whole arguments object is {}
by default, so there’s always something to destructurize.
Summary
Destructuring assignment allows for instantly mapping an object or array onto many variables.
The full object syntax:
This means that property
prop
should go into the variablevarName
and, if no such property exists, then thedefault
value should be used.Object properties that have no mapping are copied to the
rest
object.The full array syntax:
The first item goes to
item1
; the second goes intoitem2
, all the rest makes the arrayrest
.It’s possible to extract data from nested arrays/objects, for that the left side must have the same structure as the right one.
Destructuring assignment
importance: 5
We have an object:
Write the destructuring assignment that reads:
name
property into the variablename
.years
property into the variableage
.isAdmin
property into the variableisAdmin
(false, if no such property)
Here’s an example of the values after your assignment:
Solution
The maximal salary
importance: 5
There is a salaries
object:
Create the function topSalary(salaries)
that returns the name of the top-paid person.
If
salaries
is empty, it should returnnull
.If there are multiple top-paid persons, return any of them.
P.S. Use Object.entries
and destructuring to iterate over key/value pairs.
Solution
Last updated