The Spread Operator and Rest Parameters

David Chase
Jul 10, 2017 · 4 min read

Introduced with ECMAScript 6, the spread operator and rest parameters have tidied up many of the inefficiencies involved with accessing functional parameters, array concatenation, and destructuring arrays and objects. While these features are syntactically identical (…), they behave quite differently: the spread operator turns an array into its various elements, while rest parameters gather up multiple elements into a single element. Before we get into these new features, let’s take a look at what life was like before these three little dots came along.

Previously, in order to access the arguments passed to a function, we had to use the arguments object. Here’s an example of usage:

function countArgs() {
console.log(arguments.length)
}
countArgs('one', 'two', 'three')#=> 3

Simple enough, but this can get tricky when you are using nested functions and need to access both of their parameters. Since the arguments object is hardcoded, you would need to save it as a separate variable in order to access it within the nested function, as it would be redefined and overwritten by the internal function. Additionally, the arguments object is not an array, but an array-like object, so .map and other methods won’t work on it. You would first need to convert it to a true array object with .call . Look at all this extra pain:

function alphabetizeWords() {
var args = arguments
var words = removeNumbers()
return words.sort()
function removeNumbers() {
return Array.prototype.filter.call(args, element =>
typeof element !== 'number'
)
}
}
alphabetizeWords(1, 'eight', 'two', 3, 'nine', 9)#=> ['eight', 'nine', 'two']

This all seems like a lot of extra work!

Enter Rest Parameters

Rest parameters allow us to cut out these extraneous conversions and variables. For one, we can access these parameters by defining a rest parameter in our declaration. Also, we are free from having our hardcoded arguments object being overwritten by the internal function, which allows us to reference our rest parameter inside our nested function. And lastly, the rest parameter is a bonafide array, not an array-like object that we would have to convert before attempting to .map or .sort it. Let’s take a look at our refactored function using rest parameters:

function alphabetizeWords(...args) {
var words = removeNumbers()
return words.sort()
function removeNumbers() {
return args.filter(element => typeof element !== 'number')
}
}
alphabetizeWords(1, 'eight', 'two', 3, 'nine', 9)#=> ['eight', 'nine', 'two']

We get the same functionality with fewer steps, not to mention it’s much nicer to look at.

You can also utilize rest parameters to gather up an unspecified number of arguments into an array. However, the rest parameter must be defined as the last argument passed. Here is an example:

function isAbovePar(par, ...scores) {
return scores.map(score => score > par)
}
isAbovePar(4, 3, 5, 7, 2, 90)#=> [false, true, true, false, true]

Array Manipulation

The spread operator gives us new and more straightforward ways to manipulate arrays. We can more easily combine arrays and compose new arrays from elements of existing arrays using the spread operator.

With the .concat method, we can merge two arrays into a single array, but the syntax is a bit clunky. Let’s take a look:

var array1 = ['a', 'b', 'c']
var array2 = ['d', 'e', 'f']
array1 = array1.concat(array2)#=> ['a', 'b', 'c', 'd', 'e', 'f']

It seems redundant to redefine array1 in the process of calling .concat on it. Here is what array concatenation looks like using the spread operator syntax:

var cons = ['Al Capone', 'John Dillinger', 'Whitey Bulger']
var cats = ['Hobbes', 'Garfield', 'Cookie Puss']
var nations = ['Algeria', 'Laos', 'Uruguay']
var concatenation = [...cons, ...cats, ...nations]#=> ["Al Capone", "John Dillinger", "Whitey Bulger", "Hobbes", "Garfield", "Cookie Puss", "Algeria", "Laos", "Uruguay"]

*Cookie Puss is not actually a cat, but a space alien from the planet Birthday.

We can also use methods like .unshift and .push with the spread operator to efficiently combine arrays.

var array = [1, 2]
var array2 = [3, 4]
array.push(...array2)#=> [1, 2, 3, 4]

If we wanted to construct an array using an existing array as part of it, we can now use the spread operator instead of splicing and pushing:

var colors = ['yellow', 'green', 'blue']var rainbow = ['red', 'orange', ...colors, 'indigo', 'violet']#=> ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]

Object Manipulation

We can also use the spread operator to easily merge objects without the use of Object.assign.

var object = {'a': 1, 'b': 2}
var object2 = {'c': 3, 'd': 4}
var mergedObject = {...object, ...object2}#=> {
'a': 1,
'b': 2,
'c': 3,
'd': 4
}

Destructuring

One of the most powerful uses of rest syntax is destructuring arrays and objects to extract information to suit your needs. As with function calls, the rest parameter must be assigned last. Here is an example of array destructuring with rest syntax:

var bones = ['cranium', 'fibula', 'metatarsal', 'femur', 'tibia']
var headBone, legBones
[headBone, ...legBones] = bones
headBone #=> 'cranium'legBones #=> ['fibula', 'metatarsal', 'femur', 'tibia']

The rest parameter, defined last, will collect all of the remaining elements into an array.

Object destructuring follows a similar pattern:

var prices = {car: 26000, pizza: 2.5, hamburger: 5, hotDog: 2}{veryExpensiveThing, ...food} = pricesveryExpensiveThing #=> {car: 26000}food #=> {pizza: 2.5, hamburger: 5, hotDog: 2}

This new syntax makes extracting data from objects much easier!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade