Let’s say, you are moving in to a new house. Once you moved, you need to unpack the items. The plate goes to kitchen items, the cloth goes to wardrobe and the shoes go to shoe rack.
Destructuring does the same thing for us. If we want to unpack few items from an array or object, destructuring makes it easier for us.
Array Destructuring
Previously when we wanted to pull out elements from array the syntax was
let itemsBox = ['plates', 'clothes', 'shoes']
let kitchen = itemsBox[0]
let wardrobe = itemsBox[1]
let shoeRack = itemsBox[2]
After using destructuring
let itemsBox = ['plates', 'clothes', 'shoes']
let [kitchen, wardrobe, shoeRack] = itemsBox
console.log(kitchen) // plates
console.log(wardrobe) // clothes
console.log(shoeRack) // shoes
Note: Destructuring does not mutate the original array or object.
In above example, we have used array literal syntax to the left of the assignment operator.
If you decide not to take out wardrobe items for now, you can just avoid it like this
let [kitchen, , shoeRack] = itemsBox
Why is destructuring useful?
In ES5 and earlier, fetching data from arrays and objects were leading to a lot of duplicate code. Even to get data into a local variables from nested objects you need to dig through the entire structure. Destructuring provides simple looking syntax. Apart from that it has many more benefits like swapping data and parsing return values from function is much easier using destructuring.
Note: You must provide an initializer when using destructuring with var, let, const.
Swapping using destructuring
let item1 = 10
let item2 = 20
[item1, item2] = [item2, item1]
console.log(item1) // 20
console.log(item2) // 10
Parsing returned array values from a function
function calculate(a, b) {
let add = a + b
let subtract = a - b
return [add, subtract]
}
let [sum, difference] = calculate(20, 10)
console.log(sum, difference) // 30 10
Default values
If an array elements are less than the number of variables to the left side of the assignment operator, the remaining variables are considered as undefined.
We can assign default values to the variables to avoid being undefined.
let [a, b, c=5] = [1, 2]
console.log(a) //1
console.log(b) //2
console.log(c) //5
Nested array destructuring
We can descend the nested array by providing the same structure to the left of the assignment operator as to the right.
let hungryHippo = ['pizza', 'burger', ['chocolate', 'icecream'], 'noodles']
let [lunch, dinner, [sweet], snacks] = hungryHippo
console.log(lunch) // pizza
console.log(dinner) // burger
console.log(sweet) // chocolate
console.log(snacks) // noodles
Destructing with rest(…)
If we want to assign the remaining items of an array to a variable, the … syntax is used.
let itemsBox = ['plates', 'clothes', 'shoes', 'books', 'pencils', 'papers']
let [kitchen, wardrobe, shoeRack, ...stationary] = itemsBox
console.log(kitchen) // plates
console.log(wardrobe) // clothes
console.log(shoeRack) // shoes
console.log(stationary) // ['books', 'pencils', 'papers']
This technique is even used to create a clone of an array.
let [...allItems] = itemsBox
console.log(allItems) // ['plates', 'clothes', 'shoes', 'books', 'pencils', 'papers']
Note: The rest variable must be at last. Rest variable if followed by comma, will throw an error.
Object Destructuring
Object destructuring uses the object literal to the left side of the assignment operator.
let person = {
name: 'John',
age: 25
}
let {name, age} = person
console.log(name) //John
console.log(age) //25
In the above example, person.name is stored in variable name and person.age is stored in variable age.
Note: Variable declaration using const always needs initialization but even when we use var or let for object destructuring, it is must to initialize or it will throw an error.
const {name, age} // error
var {name, age} // error
let {name, age} //error
We can make assignment separate from declaration like this:
let person = {
name: 'John',
age: 25
}
let name, age
({name, age} = person)
Note: ( ) is must around destructuring assignment statement. The reason is, curly braces are considered as a block in JavaScript. Parenthesis interprets it as an expression.
Order does not matter in object destructuring.
let person = {
name: 'John',
age: 25
}
let {age, name} = person
console.log(age) //25
console.log(name) // John
Assigning different variable names
If we feel to use different variable names, we can do it like this:
let person = {
name: 'John',
age: 25
}
let {name: firstName, age: howOld} = person
console.log(firstName) //John
console.log(howOld) //25
In above example, person.name is assigned to firstName and person.age is assigned to howOld. It is opposite to the regular object syntax. In the regular syntax the key is on the left of the colon and value is on the right. In this case the value is on the left of the colon and key or name is on the right.
Default values
We can give even default values to the variables. If we don’t assign default values and the variable is not available in the object, it will automatically be trated as undefined.
let person = {
name: 'John',
age: 25
}
let {name, age, gender='male', speaks:language = 'English', somethingElse} = person
console.log(gender) //male
console.log(language) //English
console.log(somethingElse) //undefined
Nested destructuring
Nested destructuring helps to unpack only those information which we want from deep inside the object.
let person = {
name: 'John',
age: 25,
address: {
street: '4th street',
city: 'New York'
}
}
let {address:{city}} = person
console.log(city) //New York
The curly braces to the right side of the colon indicates that the destination is one more level deep into the object.
Destructuring with rest(…)
It is much similar to array destructuring with rest.
let person = {
name: 'John',
age: 25,
qualification: 'Engineer'
}
let {name, ...otherInfo} = person
console.log(otherInfo.age) // 25
console.log(otherInfo.qualification) //Engineer
console.log(otherInfo) // { age: 25, qualification: "Engineer" }
In the above example, otherInfo will behave like an object with remaining properties and values from the person object.
Array and object mixed destructuring
We can easily destructure more complex mixture of array and object together. It is very useful when we have a JSON structure.
let colors = {
favorite: 'Pink',
chart: {
primary: ['Red', 'Yellow', 'Blue'],
secondary: ['Purple', 'Green', 'Orange']
}
}
let {favorite, chart: {secondary:[first, ...others]}} = colors
console.log(favorite) // Pink
console.log(first) //Purple
console.log(others) // ['Green', 'Orange']
Object dstructuring as function parameters
let person = {
name: 'John',
age: 25
}
function getInfo({name, age}) {
return `${name} is ${age} years old.`
}
console.log(getInfo(person)) // John is 25 years old.
One more use of object destructuring is, we can pass optional parameters in function arguments.
function draw(shape, {width, length, radius}) {
// code to draw a shape
console.log(shape, width, length, radius)
}
draw('circle', {radius: 5}) // length and width are set to undefined
draw('square', {width: 10}) // length and radius are set to undefined
If the destructured parameters are not passed, they will be undefined.
Note: In above kind of function, function calling time, if we don’t pass the second argument, it will throw an error. It is because internally JavaScript engine does like this
function draw(shape, options) {
let {width, length, radius} = options
}
If the right side of an assignment operator is not passed it will evaluate as undefined and throws an error.
draw('rectangle') // throws an error
To avoid it we can set default value for second argument.
function draw(shape, {width, length, radius} = {}) {
// code to draw a shape
}
Now all the optional variables will be undefined. Even if the second argument is not passed, it will not throw any error.
Let’s summarize
- Using destructuring, it is very convenient to pull out required elements or items from an array and an object.
- To extract array data, array pattern is used and to extract object data, object pattern is used.
- In both array and object destructuring, default values can be assigned.
- In both destructuring, if right side of the assignment operator is undefined, it will throw an error.
- Destructuring declaration using var, let or const to create variable must need initializer.
- Destructuring is very useful in functions where optional parameters are used.