JavaScript: Use Destructuring Assignment over Function Parameters
A safer way to define your functions
With ES6 comes the ability to leverage destructuring assignment. For those who aren’t familiar with the syntax, it can seem a little weird. Once you understand how it works, I promise you will want to (and maybe should) use it almost everywhere.
Quick Primer on Destructuring Assignment
Destructuring assignment with objects is just a way to take any JavaScript object:
const myFoods = {a: 'apple', b: 'banana', c: 'carrot', d: 'donut'}
And pull out the parameters we want into its own variable:
const { a, b, c, d} = myFoods
If we aren’t sure a variable exists, we can easily provide a default value:
const {a = 'apple didn't exist', b, c, d} = myFoods
If we want to rename one of the variables, we can do so like this:
// we renamed a to be apple
const {a: apple, b, c, d} = myFoods
If we only want fruits (a
and b
without c
and d
), we can pick out the fruits and group the random foods by doing the following:
// you will often see "...rest" used as a convention
const {a, b, ...otherFoods} = myFoods
const carrotAndDonut = {...otherFoods}
console.log(carrotAndDonut) // prints out {c: 'carrot', d: 'donut'}
And that’s all there really is to it!
How this will replace your function parameters
Lets say we have the following function:
function printFruits(apple, banana) {
console.log(`we should have an ${apple} and ${banana}`)
}
Okay great, we expect an apple and banana. Let’s say we are using the same object as the one demonstrated in the primer:
const myFoods = {a: 'apple', b: 'banana', c: 'carrot', d: 'donut'}
We can use printFruits
as follows:
// a corresponds to apple, b corresponds to banana
printFruits(myFoods.a, myFoods.b)
But there are a few problems here
First, order of parameters matters. The following can happen very easily and cause hard to track bugs:
// an innocent swap of variables can rain hell on our software
printFruits(myFoods.b, myFoods.a)
Also, what if we want printFruits
to be smart enough to extract the fruits it expects and discard everything else? We could do the following using the ...rest
syntax in ES6 (yes, it works for function parameters too):
function printFruits(apple, banana, ...otherFruits) {
console.log(`we should have an ${apple} and ${banana}`)
}
But now we have an unused variable, which is yucky.
Okay, no problem, what if we just passed in the whole object like below:
function printFruits(myFoods) {
console.log(`we should have an ${myFoods.a} and ${myFoods.b}`)
}
printFruits(myFoods)
That’s a little better. It solves the problems above, but introduces a new one by losing the clarity of the function signature. Before, we knew immediately that we needed to pass an apple and banana. Now we have to actually look at the function definition to see what we are trying to grab out of myFoods
. Not so fun when your function spans 100 lines.
This is where destructuring assignments really shines. Here is what printFruits
looks like using destructuring assignment:
function printFruits(myFoods) {
const {a, b} = myFoods
console.log(`we should have an ${a} and ${b}`)
}
printFruits(myFoods)
We can go one step further and actually use destructuring assignments right in the function’s parameters:
function printFruits({a, b}) {
console.log(`we should have an ${a} and ${b}`)
}
printFruits(myFoods)
And if we don’t like the (purposefully vague) parameter names, we can always rename them!
function printFruits({a: apple, b: banana}) {
console.log(`we should have an ${apple} and ${banana}`)
}
printFruits(myFoods)
As well as give a default value if we try to pull out a variable that doesn’t exist:
function printFruits({a: apple = 'default apple', b: banana = 'default banana'}) {
console.log(`we should have an ${apple} and ${banana}`)
}
printFruits(myFoods)
If I’m using Flow or TypeScript, who cares?
Fair, but using this method (pun not intended) you can still free yourself from worrying about the order of parameters. Even in TypeScript, if you have two parameters that are both strings, you may accidentally swap them and be in an even worse position than non Flow / TypeScript folks because you trusted the system to catch that for you.
That being said, this is primarily for my vanilla JS folks out there who want a little more safety in their code. We shouldn’t let a type system keep us from doing our due diligence as not every project we come across as developers will make use of Flow or TypeScript.
Final Thoughts
I hope this helps shine some light on the practical benefits on destructuring assignment in JavaScript. There are plenty more applications, but this one I found to be the biggest game changer. Let me know your thoughts in the comments section!