Level Up Your JavaScript - The Power of Destructuring Explained
Encapsulation, polymorphism, and even the titular "destructuring" – the list of technical terms that can make a beginner's head spin is long. When faced with such sophisticated terminology, it's natural for any new programmer to wonder what kind of complexity lies beneath. Fortunately, it often turns out that fancy names have little to do with the actual difficulty of the underlying concept. Destructuring, now a well-established feature in JavaScript, is no exception to this rule.
What will I cover this time? Let's see:
- What is destructuring?
- Array destructuring
- Object destructuring
- Default values
- Practical applications of destructuring
What is Destructuring?
As Kyle Simpson aptly put it in his book "You Don't Know JS: ES6 & Beyond" the manual assignment of an indexed value from an array or a property from an object can be called "structural assignment."
Okay, but what does this have to do with the mysterious "destructuring"? Following Kyle's reasoning, we can expect an operation that does the opposite of what's shown in the example above. Let's see how this works in practice.
At first glance, this syntax might leave a big question mark above your head. Where did the parentheses around our variable names come from? How do values get assigned to the individual variables? Where did the returned array go?
Destructuring assignment is an expression that allows you to unpack values from arrays or properties from objects into distinct variables. This is achieved by symmetrically reversing the assignment pattern. The left-hand side is treated as a pattern for decomposing values from the array/object.
If the pattern doesn't match a value, the variable will receive the value undefined. The object returned by the bar function doesn't have an a property, so no numerical value is assigned to it. If you're having trouble understanding how the bar function works, I invite you to read my post on arrow functions. (https://www.codesmith.io/blog/exploring-arrow-functions-in-javascript)
Alright, we're able to unpack values from objects and arrays using this new, fancy syntax. Is that all destructuring has to offer?
Array Destructuring
Now that we know the basics of the syntax, we can move on to more interesting tricks.
If we want to skip a specific element, we put a comma in its place. This allows us to selectively unpack the elements of the returned array.
If we want to assign a few elements and gather the rest of the array into a separate variable, we can use the spread syntax(...).
If there are no remaining elements in the array to be gathered by the spread syntax, the variable assigned with the spread syntax will become an empty array.
It turns out that array destructuring uses an iterator to access the source values. This means we can use this syntax for any iterable value. Besides arrays, this includes strings, maps, sets, and structures returned by DOM operations.
Failed Array Destructuring
If we use array syntax like const [a, b], and try to assign from a source that isn't iterable, the engine will throw a TypeError.
If we're not 100% sure about the values being processed by destructuring (e.g., asynchronous functions), we need to be extra careful.
Object Destructuring
To destructure an object, we can use curly braces {} to create a pattern that mirrors the structure of the object you want to extract values from. Inside the curly braces, we list the properties we want to extract, using their original property names as variable names.
There's nothing stopping us from using variable names that differ from the property names of the object we're destructuring. However, this involves using syntax that might seem a bit convoluted at first.
The world is upside down, everything is reversed! As you can see, on the left-hand side, we're dealing with the pattern source -> target. Traditional assignment uses the pattern target <- source. Don't panic, as is often the case in programming, after working through a few examples, everything will fall into place.
Destructuring allows us to use computed property keys. This refers to property names calculated from the value of a variable, which is possible with a bracket notation [].
Failed Object Destructuring
When destructuring primitive values (like numbers, strings, or booleans), JavaScript temporarily converts these values to their corresponding object wrappers to access their properties. This means that destructuring will generally work as expected for these primitives. However, destructuring will fail when trying to access properties on null or undefined values, as these values have no corresponding object wrappers.
Additionally, if we start our statement with curly braces, the engine will interpret them as defining the boundaries of a block. To use destructuring, it's worth sticking to variable initialization. If we're interested in assignment, we can use the workaround with parentheses.
Default Values
In case of a mismatch between the source value, destructuring allows for optional functionality. We can protect against assigning undefined to a variable by defining a default value.
Interestingly, the default value can refer to a variable from the same pattern.
Of course, it's important to remember that the default value will only be calculated if needed. The value matched from the source takes precedence.
Practical Applications of Destructuring
We've managed to gather quite a bit of new syntax. Let's see how this translates into our problem-solving skills.
Destructuring arrays returned by methods
JavaScript has a dozen built-in methods that return arrays. Often, we care about specific elements, not the array itself. A good example begging for destructuring is String.prototype.split()
Importing Specific Functionality
Destructuring can be a powerful tool when importing specific functions or variables from a module. Instead of importing an entire module, we can import only the parts we need. Here’s an example of how to use destructuring with CommonJS to import specific functions from a module:
For instance, if we have a module named utility-functions that exports multiple functions, but we only need calculateSum and findMax, we can import just those.
This way, we can keep our code cleaner and only include the functionality we need from external modules.
Swapping Values
Swapping values traditionally requires a temporary variable, which can make the code less elegant. However, with destructuring, we can achieve this more cleanly and concisely.
Parameter Destructuring
I saved the best for last. Many of the functions we write take an object as a parameter. Typically, we need to check if the parameter is undefined and then set default values for each property before moving on to the actual function logic. This results in a lot of code lines with little benefit. Fortunately, destructuring greatly improves our situation.
With destructuring, we can directly unpack and assign default values to object properties within the function's parameter list. This eliminates the need for those repetitive checks and assignments, resulting in more concise and readable functions.
Summary
Destructuring offers an elegant way to work with data in JavaScript, whether it's pulling values from arrays, objects, or even function arguments. By taking advantage of this feature, you'll write cleaner, more maintainable code that's ready for the challenges of modern JavaScript development. And this is just the beginning – as you explore more advanced JavaScript concepts (and libraries like React), you'll find that destructuring becomes an invaluable part of your toolkit.
The MDN documentation on destructuring: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment