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 manually
    const 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

  • these are shallow copies
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

  • order doesn't matter
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

  • these are shallow copies
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

Copyright © 2022