JavaScript is an... interesting... language. I personally love it, but can see why others wouldn't be so fond of it. ECMAScript 6, a.k.a. ES6, introduced a good handful of really nice features that make JavaScript development more enjoyable. In this short post, I want to talk a little bit about destructuring assignment and provide some practical examples where this might be useful.
MDN describes destructuring assignment in the following way:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
This means that you can take an array or object, and easily pluck out values from it and assign them to variables.
Destructuring Assignment with Objects
Suppose you've got an object representing a point in 3-dimensional space:
let myPointInSpace = {
x: 3,
y: -2,
z: 2.7
}
Suppose you want to do some computing with the coordinates of the point [like compute its distance from the origin, (0, 0, 0)], so you'd like to throw the x
, y
, and z
coordinates of the point in some variables for easy reference. One might do the following:
let x = myPointInSpace.x;
let y = myPointInSpace.y;
let z = myPointInSpace.z;
let distance = Math.sqrt(x*x + y*y + z*z);
This certainly works! But if you do that enough times, you might get sick of copy/pasting. With destructuring assignment, you can pluck those coordinates in a much more succinct way! Here's how:
let {x, y, z} = myPointInSpace;
let distance = Math.sqrt(x*x + y*y + z*z);
The curly-braces in this case indicate the destructuring assignment. The first line above looks at the myPointInSpace
variable, and looks for any properties indicated within the curly-braces, and will return those back in individual variable assignments.
Conveniently, you can pluck only a subset of an object's property-values. For example, if you just needed the x
and y
coordinates, you could just as well do:
let {x, y} = myPointInSpace;
Destructuring Assignment with Arrays
Destructuring assignment is great when used with objects, but it can also be used with arrays in a similar way. Let's suppose that instead our point in space is represented as a 3-tuple (or array of 3 values).
let myPointInSpace = [3, -2, 2.7];
The old-school way of plucking the coordinates of this point would be:
let x = myPointInSpace[0];
let y = myPointInSpace[1];
let z = myPointInSpace[2];
With destructuring assignment, we can shorten this to:
let [x, y, z] = myPointInSpace;
Pretty neat!
Some real examples
I read about destructuring assignment a few times before I actually made use of it and appreciating its utility. I showed a simple example above that involved simply plucking values, but I want to showcase a couple more useful examples.
Setting Default Function Values
When writing functions, I often like to use a single object as the input, and then pull values from that object - that way I don't have to worry about the order of my inputs. Destructuring assignment helps with this, and allows us to make use of "default parameters" that were introduced in ES6.
Let's say you want to write a function that takes a number of hours, minutes, and seconds and converts that amount of time into a number of milliseconds. We can do this via the following:
let toMilliseconds = ({
hours = 0,
minutes = 0,
seconds = 0
}) => {
// Compute the # of ms
let ms = (hours * 60 * 60 * 1000) + (minutes * 60 * 1000) + (seconds * 1000);
// Return the # of ms
return ms;
}
This might look like a strange function declaration, but it entails that we can pass in an object as the input to toMilliseconds()
and the function will look for keys hours
, minutes
, and seconds
to use. If it doesn't find any one of those keys in the object that was passed in, it will just default to 0. Putting this to use might look like the following:
let ms1 = toMilliseconds({hours: 3, minutes: 42, seconds: 33});
let ms2 = toMilliseconds({minutes: 7});
In the second line above, hours
and seconds
get defaulted to 0 and we don't have to explicitly pass a number of hours or seconds.
I've grown to like this way of writing functions, as some functions have a lot of a lot parameters that all need defaults - and this form of a function declaration feels readable to me.
Swapping Values
Swapping variables' values is a somewhat common procedure, and often involves creating a temporary variable. Here's a classic example of this.
// Initial values
let x = 5;
let y = 3;
// Now swap, creating tmp variable
let tmp = y;
y = x;
x = tmp;
delete tmp;
However, destructuring assignment makes this more succinct, and in my opinion, a little more readable:
// Initial values
let x = 5;
let y = 3;
// Now swap
[x, y] = [y, x];
If you find yourself swapping variables often, destructuring can be a real nice tool.
Pulling Values and Giving New Names
With object destructuring, you can actually name your variables things other than the keys of the object you are destructuring. Suppose you're using an API, and the API sends back a response where the object has weird names that you don't prefer to use. Something like the following:
let apiResponse = {
someWeirdKeyForX: 3,
someWeirdKeyForY: -7
}
We could pull the x
and y
values out of that response and name them whatever we'd like - say x
and y
. To do this, we use the following syntax:
let {someWeirdKeyForX: x, someWeirdKeyForY: y} = apiResponse;
The someWeirdKeyForX: x
part of the destructuring declares that you want to pull the key someWeirdKeyForX
from apiResponse
and you'd like to assign it to a variable named x
. This can be surprisingly useful. Realistically, I like to use this in scenarios as simple as assigning something like apiResponse.latitude
to lat
and apiResponse.longitude
to lng
.
Look out!
One little "gotcha" that I stumbled on a few times was the fact that sometimes you need to wrap your destructuring statements in parentheses. If your destructuring statement doesn't start with a variable declaration keyword (like var
, let
, or const
), you'll need to wrap your statement in parentheses. I'm assuming this is so the compiler knows how to distinguish between the { ... }
in the destructuring statement and the { ... }
that indicate blocks of code.
Here's what I mean by this. Consider the following code:
// Declare x and y ahead of time
let x, y;
// Object that we will destructure
let o = {x: 3, y: -7};
// Try to destructure
{x, y} = o; // -> No good!
The compiler doesn't know how to interpret that last line of code. You'll need to change it to:
// Declare x and y ahead of time
let x, y;
// Object that we will destructure
let o = {x: 3, y: -7};
// Successfully destructure
({x, y} = o); // -> Good!
If you find yourself using destructuring, make sure you're aware of this little caveat!
And more!
MDN has many more examples of destructuring assignment. If you want to know more, check that page out.
In my next post, we'll take a dive into the rest and spread operators in Javascript, and see how they play into destructuring assignment.
Top comments (2)
Nice reminder of all the possibilities of destructuring with clear examples.
Nice, Thank