ES6 Rest/Spread Operator Usage

We all know that the javascript (...) rest/spread operator has made our lives easier with ES6. I wanted to show you how it is used and a couple of ways that you can use it.

Cory House and others have some fantastic courses on @Pluralsight about the great new features of ES6
Start your Free Trial today!

Start a 10-day free trial at Pluralsight

Rest parameters to functions

Functions have the magic arguments variable, but it is not very clean, and it’s not actually an array member. So you can’t use the array functions on it like map, slice etc.


  function concat () {
    return Array.prototype.slice.call(arguments).join(' ')
  }
  var result = concat('this', 'is', 'hard')
  console.log(result)
  // 'this is hard'

Instead, we can provide a named parameter prefixed by ... that will spread the parameters that come in into an array.


  function concat (...words) {
    return words.join(' ')
  }
  var result = concat('this', 'is', 'better')
  console.log(result)
  // 'this is better'

You can also have specific named parameters, followed by an arbitrary number of additional parameters that are spread.


  function multiply(multiplier, ...numbers) {
    return numbers.map(element => {
      return multiplier * element;
    });
  }

  var arr = multiply(2, 1, 2, 3);
  console.log(arr); // [2, 4, 6]

You can break down your arrays or objects into individual properties if the function you’re calling wants individual parameters, without using apply. Or even, mix and match.


  console.log(1, 2, 3); // '1 2 3'

  console.log.apply(console, [1, 2, 3]); // '1 2 3'

  console.log(...[1, 2, 3]); // '1 2 3'

  console.log(1, ...[2, 3, 4], 5) // '1 2 3 4 5'

Another very good bonus is that it can be used on anything that is an iterable. So if you’re working with nodes/dom elements that aren’t arrays, but are still a list of things you want to work with, you can spread them into a real array that you can work with.


  [...document.querySelectorAll('div')]
  // [<div>, <div>, <div>]

Composition and Destructuring of objects

We can easily grab properties from one object and add them to another.


  const one = { a: 1, b: 2 };
  const two = { c: 3, d: 4 };
  const three = { ...one, ...two };

  // three = { a: 1, b: 2, c: 3, d: 4 };

  // Then pull off a specific property
  const { d, ...thing } = three;

  // thing = { a: 1, b: 2, c: 3 };

  // assign that specific value to another variable
  let otherVar;
  const { d: otherVar, ...thing } = three;
  // otherVar = 4

Adding properties with dynamic/unknown property names. Maybe a React reducer handling a dictionary with keys? We can use [] with a string to give a named property key for an object. The spread operator also is convenient in React reducers where you don’t want to mutate the previous state coming in, rather composing a new state based off the old state. ... will create a copy of an old object/array. Be careful, as spreading arrays of objects will still keep a reference, so it isn’t a copy per se.


  // state = { 1: 'hello', 2: 'welcome' }
  // action = { type: 'add', id: 3, payload: 'goodbye' }
  reducer(state, action) {
    switch(action.type) {
      case: 'add':
        return { ...state, [action.id]: action.payload };
        // returns a new object { 1: 'hello', 2: 'welcome', 3: 'goodbye' }
        // All accomplished on one line!
    }
  }

How about pulling a dynamically named property off of an object?


  // state = { 1: 'hello', 2: 'welcome', 3: 'goodbye' }
  // action = { type: 'remove', id: '2' }
  reducer(state, action) {
    switch(action.type) {
      case: 'remove':
        const {[action.id]: _, ...rest } = state;
        return rest;
        // returns a new object { 1: 'hello', 3: 'goodbye' }
        // We assigned the destructured property to a 'throw-away'
        // variable _
        // Unfortunately, we can't just pull off dynamically
        // named properties, yet.
        // We have to assign them to a throw-away
    }
  }