Rest parameter Vs. spread operator

Both of them used the (...) syntax (three-dot). even though they are syntactically are the same, they differ from what they do. here are my unofficial (or how i tell my friend) definition of what is rest parameter and spread operator, starting with the rest parameter.

Rest parameter

How I tell my friend:
Rest Parameter: it’s always going to be used at the end of array/object(when you are using destructuring on array or object) or function parameters. and you are going to used to collect/gather the remaining element into an array (it can be an object when you are destructuring an object)

Official:
The rest parameter syntax allows a function to accept an indefinite number of arguments as an array.link

Rest Operator example:

function sum(first, ...rest) {
  for (var i = 0; i < rest.length; i++) {
    first += rest[i];
  }
  return first;
}
console.log(sum(1, 2, 3, 4)); // answer: 10

here as you can see the first is equal to 1 and the ...rest is equal to [2, 3 ,4]. so basically the ...rest is collecting/gathering the remaining arguments which are [2, 3, 4].
And it doesn’t matter you can pass as many arguments as you like here is the example:

function sum(first, ...rest) {
  for (var i = 0; i < rest.length; i++) {
    first += rest[i];
  }
  return first;
}
console.log(sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); // answer: 91

Now if you are use the ...rest at first you are going to see an error:

function sum(...rest, first) {
  for (var i = 0; i < rest.length; i++) {
    first += rest[i];
  }
  return first;
}
console.log(sum(1, 2, 3, 4)); 

//function sum(...rest, first) {
                      ^
//SyntaxError: Rest parameter must be last formal parameter

Next examples are going to be about when you are using Destructuring assignment. (learn about Destructuring assignment)

const test = ["daniel hemmati", "yourname", "age", 1, 2, 3];
const [zeroIndex, ...rest] = test;
console.log(zeroIndex); // 'daniel hemmati'
console.log(rest); //[ 'yourname', 'age', 1, 2, 3 ]

Object destructuring

const goodOldObject = {
  learning: "rest operator",
  why: "because you are good developer",
  happyCoding: true,
};

const { learning, ...rest } = goodOldObject;
console.log(learning); // rest opeartor
console.log(rest); // { why: 'because you are good developer', happyCoding: true }

Why not using arguments object instead of rest parameter?

  1. first of all arguments is not a real array, it’s an array-like object so you don’t have access to map, filter, reduce and many other array methods on arguments.
  2. And you can’t use arguments in arrow function.
    And if even if you want to turn the arguments to the actual array, you have to add some boilerplate code.
    Here is the comparison of the code length between using arguments vs rest parameter for sorting an array of numbers.
// with arguments object 
function withArguments(a, b, c) {
  // this will turn it to array
  let normalArray = Array.prototype.slice.call(arguments); 
    
  // or use this method 
  let normalArray2 = [].slice.call(arguments);
  // or this 
  let normalArray3 = Array.from(arguments);

  return normalArray.sort((a, b) => a - b);
}

console.log(withArguments(3, 2, 1));

As you can see there are three ways to turn arguments object into an array.

Sorting an array with rest operator.

// with rest operator
function withRest(...rest) {
  return rest.sort((a, b) => a - b);
}

console.log(withRest(3, 4, 2, 1));

And as you can see we can pass as many arguments we want to withRest function. (i mean come on, that’s amazing that we can do that with three dot).

Spread operator

Official:
Spread operator: (...) allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected. source

How i tell my friend:
Spread operator: you have iterables like array / object / strings and you want to expand it into a single arguments/elements.

For now we just saw that how we can get an array form the list of parameters. like witRest function.
But sometimes we want to do a exactly the reverse of that.

For instance we have a built-in function in Javascript Math.max which return the greatest number from a list of numeric number:

console.log(Math.max(3,5,1))// answer: 5

Now what if we have array of number? Does it work if we pass an array of numbers?

let res = [2, 5, 1, 4, 9, 3];
console.log(Math.max(res)); // NaN

The reason is that Math.max accept the numeric arguments not a single array. Now in the past in order to pass an array of numbers to a Math.max you had to write some extra code to get the result you wanted. Here is the code:

let numbers = [3, 1, 0, 6, 4, 9, 5];
console.log(Math.max.apply(null, numbers)); //  9

Here is spread operator for rescue. instead of writing all of that Math.max.apply(null, number) we can do this:

let res = [2, 5, 1, 4, 9, 3];
console.log(Math.max(...res)); // 9

Now that’s really cool. basically when ...res is used on a function call, it expands an iterable object ...res into the list of arguments.

NOTE: if you log the ...res you will see the output is a list of number.

let res = [2, 5, 1, 4, 9, 3];
console.log(...res) // 2 5 1 4 9 3

You even pass multiple array of numbers and spread it to the Math.max

let input1 = [1, 5, 3, 0, 4, 7];
let input2 = [2, 5, 1, 4, 9, 3];
console.log(Math.max(...input1, ...input2));// answer: 9

Or even we can combine this two array with normal values like this:

let input1 = [1, 5, 3, 0, 4, 7];
let input2 = [2, 5, 1, 4, 9, 3];
console.log(Math.max(...input1, 10, 11 ...input2));// answer: 11

NOTE: unlike rest parameter it doesn’t matter where do you put spread operator, it can be at first, middle, or even at the end.

A better way to concatenate array using spread operator

In the past of we concatenate array like this:

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];

arr1 = arr1.concat(arr2);

console.log(arr1);

Here is the spread syntax of it

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
arr1 = [...arr1, ...arr2];
console.log(arr1); // [ 1, 2, 3, 4, 5, 6 ]

Pass elements of an array to a function using spread operator

This is how we used to do it:

function spreadIt(a, b, c) {
  return a + b + c;
}

let arr = [1, 2, 3];
console.log(spreadIt.apply(null, arr)); // answer: 6

Now we can do it with spread operator like this.

function spreadIt(a, b, c) {
  return a + b + c;
}
let arr = [1, 2, 3];
console.log(spreadIt(...arr))

Copy array with spread operator

How we did it before

let arr = [1, 2, 3];

// this two basically copy array 
// you are going to see more slice method rather Array.from()
let arr2 = arr.slice();

// older method 
let arr3 = Array.from(arr);

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

So if i push number to arr2 the arr will not changed.

And we can do same thing with spread operator

let arr = [1, 2, 3];
let arr2 = [...arr];
console.log(arr2);// [1, 2, 3]

Spread operator in object literals

It’s basically like what we did in array but this time for object.
We can spread one object into another object OR we can merge two object into a new object OR we can copy the object

let daniel = { name: "daniel", lastname: "hemmati" };

let obj1 = { foo: "bar", x: 42 };
let obj2 = { foo: "baz", ...daniel, y: 13 }; // danile is spreaded into obj2 LOL

let mergeObject = { ...obj1, ...obj2 };

let copyObject = { ...mergeObject };

console.log(obj2); // { foo: 'baz', name: 'daniel', lastname: 'hemmati', y: 13 }
console.log(mergeObject); // { foo: 'baz', x: 42, name: 'daniel', lastname: 'hemmati', y: 13 }
console.log(copyObject); // { foo: 'baz', x: 42, name: 'daniel', lastname: 'hemmati', y: 13 }

Summary

That’s a warp for spread operator and rest parameter. so whenever you see ... it’s either rest or spread operator.
The easy way to distinguish between them:

  • When the ... is at the end of the function parameter, it’s rest parameter, if it’s on the left side of assignment (when we did destructuring assignment) again it’s rest parameter.
  • The spread operator occurs on a function call, or on the right side of the assignment (when you spread one array into another array you did on the right side of the assignment)
    left side of assignment = right side assignment

Leave a Reply

Your email address will not be published. Required fields are marked *