Destructuring
- a way of unpacking values from an array or an object into separate variables --- to break a complex data structure down into a simpler data structure like a variable
Arrays
Basic Example
- standard retrieving of elements without destructuring:
const arr = [2, 3, 4] const a = arr[0] const b = arr[1] const c = arr[2]
- we use
[]
brackets for destructuring arrays- when the
[]
brackets are on the left side of the assignment operator it is for destructuring, rather than assigning
- when the
- with destructuring:
const [x, y, z] = arr console.log(x, y, z); // 2 3 4
- the original array is left unchanged
console.log(arr); // ▶︎(3) [2, 3, 4]
Expanded Example
starter code:
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
}
Unpacking Specific Elements
- don't have to unpack all the values from an array --- leave blank spaces for skipped elements
const [first, second] = restaurant.categories console.log(first, second) // Italian Pizzeria
const [first, , second] = restaurant.categories console.log(first, second) // Italian Vegetarian
Switching Elements
let [main, , secondary] = restaurant.categories
console.log(main, secondary) // Italian Vegetarian
- without destructuring
const temp = main main = secondary secondary = temp console.log(main, secondary) // Vegetarian Italian
- with destructuring
[main, secondary] = [secondary, main] console.log(main, secondary) // Vegetarian Italian
Destructuring a Returned Array
- can immediately destructure it --- no need to save it first or anything
const restaurant = { name: 'Classico Italiano', location: 'Via Angelo Tavanti 23, Firenze, Italy', categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'], starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'], mainMenu: ['Pizza', 'Pasta', 'Risotto'], order: function(starterIndex, mainIndex) { return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]] }, } const [starter, mainCourse] = restaurant.order(2, 0) console.log(starter, mainCourse) // Garlic Bread Pizza
Nested Arrays
- unpacking the nested array
const nested = [2, 4, [5, 6]] const [i, , j] = nested console.log(i, j) // 2 ▶(2) [5, 6]︎
- to unpack the individual values in the nested array we have to do a nested destructuring
const nested = [2, 4, [5, 6]] const [i, , [j, k]] = nested console.log(i, j, k) // 2 5 6
Setting Default Values
- useful if we don't know the length of the array
(in the following examples pretend we don't know how long the assigned array is)
- what happens without default values
// pretend we don't know how long the assigned array is const [p, q, r] = [8, 9] console.log(p, q, r) // 8 9 undefined
- with default values set
const [p = 1, q = 1, r = 1] = [8, 9] console.log(p, q, r) // 8 9 1
const [p = 1, q = 1, r = 1] = [8] console.log(p, q, r) // 8 1 1
Objects
- uses
{}
braces instead of the[]
brackets used above for arrays
new version of the starter code:
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
operatingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open:11,
close: 23,
},
sat: {
open: 0, // open 24 hours
close:24
},
},
order: function(starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]]
}
}
Unpacking Properties
- order doesn't matter for an object, so no need to skip elements
- we must have the exact property/key names
const {name, operatingHours, categories} = restaurant
console.log(name, operatingHours, categories) // Classio Italiano
// ▶{thu: {...}, fri: {...}, sat: {...}}
// ▶(4) ["Italian", "Pizzeria", "Vegetarian", "Organic"]
Changing the Property/Key Names
const {
name: restaurantName,
operatingHours: hours,
categories: tags
} = restaurant
console.log(restaurantName, hours, tags) // Classio Italiano
// ▶{thu: {...}, fri: {...}, sat: {...}}
// ▶(4) ["Italian", "Pizzeria", "Vegetarian", "Organic"]
Setting Default Values
const {menu = [], starterMenu: starters = []} = restaurant
console.log(menu, starters) // []
// ▶(4) ["Focaccia", "Buschetta", "Garlic Bread", "Caprese Salad"]
- most of the time our data won't be hardcoded (it will come from an API, etc) so we won't always know exactly what the data looks like, so it can be helpful to set defaults
Mutating Variables
let a = 111
let b = 999
const obj = {a: 23, b: 7, c: 14}
// we want to overwrite 'a' and 'b' with the new values in the object
- can't use
const {a, b} = obj
to destructure becausea
andb
are already assigned - don't want to use
let {a, b} = obj
because it would create new variables instead of using the ones already created {a, b} = obj
gives usUncaught SyntaxError: Unexpected token '='
because when we start a line with a curly brace JS expects a code block --- so we have to wrap the whole thing in parentheses
let a = 111
let b = 999
const obj = {a: 23, b: 7, c: 14}
({a, b} = obj)
console.log(a, b) // 23 7
Nested Objects
(for the following examples assume `operatingHours has already been unpacked)
- getting the
fri
object fromoperatingHours
const {fri} = operatingHours console.log(fri) // ▶{open: 11, close: 23}
- getting
open
andclose
from thefri
object in theoperatingHours
objectconst {fri: {open, close}} = openingHours console.log(open, close) // 11 23
- could also rename the variables while unpacking
const { fri: {open: o, close: c} } = openingHours console.log(o, c) // 11 23
Parameters as Objects
- the function will destructure the object so the params can be used
- it's nice because you don't need to know the order of the parameters
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
operatingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open:11,
close: 23,
},
sat: {
open: 0, // open 24 hours
close:24
},
},
order: function(starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]]
},
orderDelivery: function ({starterIndex, mainIndex, time, address}) {
console.log(`Order recieved! ${this.starterMenu[starterIndex]} and ${this.mainMenu[mainIndex]} will be delivers to ${address} at ${time}`)
},
}
restaurant.orderDelivery({
time: '22:30',
address: 'Via del Sol, 21',
mainIndex: 2,
starterIndex: 2,
})
// Order received! Garlic Bread and Risotto will be delivered to Via del Sol, 21 at 22:30
- we can use still set defaults
const restaurant = { name: 'Classico Italiano', location: 'Via Angelo Tavanti 23, Firenze, Italy', categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'], starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'], mainMenu: ['Pizza', 'Pasta', 'Risotto'], operatingHours: { thu: { open: 12, close: 22, }, fri: { open:11, close: 23, }, sat: { open: 0, // open 24 hours close:24 }, }, order: function(starterIndex, mainIndex) { return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]] }, orderDelivery: function ({ starterIndex = 1, mainIndex = 0, time = '20:00', address, }) { console.log(`Order recieved! ${this.starterMenu[starterIndex]} and ${this.mainMenu[mainIndex]} will be delivers to ${address} at ${time}`) }, } restaurant.orderDelivery({ address: 'Via del Sol, 21', starterIndex: 1, }) // Order received! Bruschetta and Pizza will be delivered to Via del Sol, 21 at 20:00