Spread and Rest (...) (ES6)
The Spread Operator
- expands an array into all its elements --- basically, unpacking all the array elements at once
- actually, it works on other things as well, but to start we are going to focus just on arrays
- used on the RIGHT side of the assignment operator
- we want to make
arr
into a new array but with some new things at the beginning --- we would need to loop over it or do it manuallyconst arr = [7, 8, 9]
// nope. doesn't do what we want because the arrays are nested
const wrongFormatArr = [1, 2, arr]
console.log(wrongFormatArr) // ▶(3) [1, 2, Array(3)]
// manually --- imagine if `arr` had thousands of elements --- not practical
const badNewArr = [1, 2, arr[0], arr[1], arr[2]]
console.log(badNewArr) // ▶(5) [1, 2, 7, 8, 9]
// with spread operator
const newArr = [1, 2, ...arr]
console.log(newArr) // ▶(5) [1, 2, 7, 8, 9]
...
takes all the elements out of arr
and writes them individually into newArr
- we can use the spread operator whenever we would normally use multiple values separated by commas --- this situation occurs every time we write an array literal and when we pass arguments into functions
console.log(...newArr) // 1 2 7 8 9
// same as writing:
console.log(1, 2, 7, 8, 9) // 1 2 7 8 9
- we want to add a new item to the main menu list (this is continuing with the example code started in destructuring.md)
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}`)
},
}
const newMenu = [...restaurant.mainMenu, 'Gnocci']
console.log(newMenu) // ▶(4) ["Pizza", "Pasta", "Risotto", "Gnocci"]
- this a completely new array, we have not manipulated
restaurant.mainMenu
- spreading arrays gets their values out similarly to destructuring, except you always get all the values and it doesn't create new variables => we can only use it places where we would write values separated by commas
Copying Arrays
const mainMenuCopy = [...restaurant.mainMenu]
console.log(mainMenuCopy) // ▶(3) ["Pizza", "Pasta", "Risotto"]
Joining Arrays
const menu = [...restaurant.starterMenu, ...restaurant.mainMenu]
console.log(menu) // ▶(7) ["Focaccia", "Bruschetta", "Garlic Bread", 'Caprese Salad", "Pizza", "Pasta", "Risotto"]
Iterables
- iterables are arrays, strings, maps, and sets (but NOT objects)
const str = 'Jonas'
const letters = [...str, ' ', 'S.']
console.log(letters) // ▶(7) ["J", "o", "n", "a", "s", " ", "S."]
// console.log(`${...str} Schmedtmann`) // Uncaught SyntaxError: Unexpected token '...'
- the second one didn't work because it is not a place where we expect separate values separated by commas => we can usually only use this operator when we are passing arguments to a function or building an array
Make New Objects that Contain Existing Objects
const newRestaurant = {foundedIn: 1998, ...restaurant, founder: 'Guiseppe'}
console.log(newRestaurant) // get a new object that is just like our original restaurant object but with the two additional properties we just supplied
Copying Objects
const restaurantCopy = {...restaurant}
restaurantCopy.name = 'Ristorante Roma'
console.log(restaurantCopy) // has new name
console.log(restaurant) // still has original name
Passing Parameters to Functions
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}`)
},
orderPasta: function (ing1, ing2, ing3) {
console.log(`Here is your delicious pasta with ${ing1}, ${ing2}, and ${ing3}.`)
},
}
// get the pasta ingredients from the user in prompts
const ingredients = [
prompt('Let\'s make Pasta! Ingredient 1?'),
prompt('Ingredient 2?'),
prompt('Ingredient 3?')
]
restaurant.orderPasta(...ingredients) // prints the string in `orderPasta` with the ingredients entered in the prompts
Rest Pattern and Parameters
- same syntax as the spread operator but used on the LEFT side of the assignment operator with destructuring
Destructuring
- must be the last element so it can collect the 'rest' --- can't be anything after all remaining elements
- this means there can also only ever be one
const [a, b, ...others] = [1, 2, 3, 4, 5]
console.log(a, b, others) // 1 2 ▶(3) [3, 4, 5]
- first and second elements assigned to
a
and b
and the rest of the elements are combined into one array, others
using the rest pattern
Combining Rest Pattern and Spread
const [pizza, , risotto, ...otherFood] = [...restaurant.mainMenu, ...restaurant.starterMenu]
console.log(pizza, risotto, otherFood) // Pizza Risotto ▶(4) ["Focaccia", "Bruschetta", "Garlic Bread", 'Caprese Salad"]
- notice that 'Pasta' from
mainMenu
was skipped, not combined into otherFood
Objects
- no skipped properties because objects have no order
const {sat, ...weekdays} = restaurant.operatingHours
console.log(weekdays) // ▶ {thu: {...}, fri: {...}}
Functions
- use rest parameters to make functions with an arbitrary amount of arguments
const add = function(...numbers) {
let sum = 0
numbers.forEach(number => {
sum += number
})
return sum
}
add(2, 3) // 5
add(5, 3, 7, 2) // 17
add(8, 2, 5, 3, 2, 1, 4) // 25
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}`)
},
orderPasta: function (ing1, ing2, ing3) {
console.log(`Here is your delicious pasta with ${ing1}, ${ing2}, and ${ing3}.`)
},
orderPizza: function (mainIngredient, ...additionalIngredients) {
// just going to log them here, but really you'd do something with the ingredients
console.log(mainIngredient)
console.log(additionalIngredients)
},
}
restaurant.orderPizza('mushrooms', 'onion', 'olives', 'spinach') // mushrooms
// ▶(3) ["onion", "olives", "spinach"]
restaurant.orderPizza('pepperoni') // pepperoni
// []
Combining Rest Parameters and Spread
const x = [23, 5, 7]
add(...x) // 35
- spread unpacks them in the call, then repacks them in the function