ES6 / JS2015 : Rest and Spread operators

A few guys I work with wanted to improve their ES6/JS2015 knowledge. We decided to take turns presenting a new ES6 feature to each other periodically. This is one of those discussions.

The Rest and Spread operators added in ES6 / JS2015 drastically improve the ability to deal with unknown numbers of function parameters, and array and hash manipulation.

The Rest Operator

This operator is an improvement to the way function parameters are handled, allowing us to more easily handle a variable number of function parameters.

Javascript has always allowed a variable number of function parameters, and reserved the arguments variable for exposing these.

For example:

function add() {
  var result = 0;
  for(var i = 0; i < arguments.length; i++) {
    result += arguments[i];
  }
  return result;
}

add(); // 0
add(1); // 1
add(1, 2, 3); // 6

The problem with arguments is that is is not a real Javascript array. It is an array-like object that provides a length and access to values like an array.

This problem can arise if you try to use the Array.prototype.reduce() function:

function add() {
  return arguments.reduce((sum, next) => sum + next);
}

add(1, 2, 3); // TypeError: arguments.reduce is not a function

Since arguments isn’t a real array, it does not include any of the functions defined on Array.prototype.

We can solve this by using the Rest operator instead. This operator takes the form ...variableName as the last parameter to a function. It will assign to variableName all the remaining parameters after those that were already assigned.

So to simplify the add() example:

function add(...numbersToAdd) {
  return numbersToAdd.reduce((sum, next) => sum + next);
}

add(1, 2, 3); // 6

In this example, numbersToAdd is an Array and is assigned the parameters [1, 2, 3].

Rest parameter with other parameters:

When other assignments come before the rest parameter, those assignments will be made first.

function doMath(operator, ...numbers) {
  console.log(operator);
  console.log(numbers);
}

doMath('add', 1, 2, 3);
// operator = 'add' (string)
// numbers = [1, 2, 3] (array)

The rest operator must be the last parameter to a function.

function add(a, ...b, c) {}
// SyntaxError: Rest parameter must be last formal parameter

The Spread Operator

The spread operator has the same appearance as the Rest parameter operator (...variableName), but appears in a different place in the code.

While they are syntactically similar, they actually perform almost the opposite function. The Spread operator is used to turn an Array of values into what is essentially a comma-separated list of parameters to pass into something else.

The Rest operator is only allowed in function parameters, and the Spread operator is used in one of three ways:

Spread in function calls

The spread operator can be used to turn an array of values onto a set of function parameters. Returning to our add() example:

function add(...numbersToAdd) { // This is a Rest parameter
  return numbersToAdd.reduce((sum, next) => sum + next);
}

var numbers = [1, 2, 3];
add(...numbers); // this is a Spread operator
// The above is functionally the same as:
add(1, 2, 3);

This is extremely useful when you have an unknown (at dev time) number of arguments that you want to pass to a function. You can .push() several values into an array then use them as parameters to a function.

Spread in array assignments

You can also use a Spread operator to make a new Array that contains values from another Array:

var array1 = [2, 3];
var array2 = [1, ...array1, 4, 5];

// array1 = [2, 3];
// array2 = [1, 2, 3, 4, 5];

Spread operator in destructuring assignments

Object and Array “destructuring” is another new ES6 feature so will be a topic of a later discussion, but the Spread operator can be used a lot like the “rest” operator to get “the remaining things” from a destructuring assignment:

// Array destructuring
var numbersArray = [1, 2, 3, 4, 5];
var [first, second, ...remaining] = numbersArray;

console.log(numbersArray); // [1, 2, 3, 4, 5] (stays unchanged)
console.log(first); // 1 (number)
console.log(second); // 2 (number)
console.log(remaining); // [3, 4, 5] (array)

A similar behavior will be achievable in the future in ES7’s Object destructuring (not supported as of Chrome 50), but is already available in Babel:

// Object destructuring
var someObject = {
  a: 1,
  b: 2,
  c: 3,
  d: 4
};
var {a, b, ...remaining} = someObject;

console.log(someObject); // {a: 1, b: 2, c: 3, d: 4} (stays unchanged)
console.log(a); // 1 (number)
console.log(b); // 2 (number)
console.log(remaining); // {c: 3, d: 4} (object)

This can be incredibly useful for manipulating hashes, or removing certain properties from an object before passing it on to another function call.

Advertisements
Tagged with: ,
Posted in JavaScript, Programming

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

CodingWithSpike is Jeff Valore. A professional software engineer, focused on JavaScript, Web Development, C# and the Microsoft stack. Jeff is currently a Software Engineer at Virtual Hold Technologies.


I am also a Pluralsight author. Check out my courses!

%d bloggers like this: