DEV Community

John Au-Yeung
John Au-Yeung

Posted on • Originally published at thewebdev.info on

JavaScript Best Practices — Rest Operator

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll look at why using the rest operators are better than their older alternatives.

Using Rest Parameters Instead of the arguments Object

Rest parameters are the best way to get all the arguments from a function. It works with all kinds of functions.

Whereas the old arguments object only works with old-style traditional functions.

The rest operator is denoted by the ... symbol in the function argument.

We can use it to put all arguments into an array or just arguments that haven’t been set as values of existing parameters that comes before the rest parameter expression.

For instance, if we have the following function:

const foo = (a, b, ...args) => console.log(a, b, args);

Then when we call it as follows:

foo(1, 2, 3, 4, 5);

We get that a is 1, b is 2, and c is the array [3, 4, 5] .

As we can see, the arguments that haven’t been set as the values of the parameters of the function are all put into an array which we can manipulate easily.

We can also put all arguments into an array by writing the following:

const foo = (...args) => console.log(args);

Then we get that args is [1, 2, 3, 4, 5] when we call it by writing foo(1, 2, 3, 4, 5); .

As we can see, rest parameters works great with arrow functions. It works equally well with traditional functions.

This is much better than what we’re doing before, which is using the arguments .

If we go back to using the arguments , then we have to use traditional functions since arrow functions don’t bind to the arguments object.

For instance, we’ve to define a function as follows to use it:

function foo() {
  console.log(arguments);
}

Then we call it as follows:

foo(1, 2, 3, 4, 5);

We get:

Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]

in the console log output.

This is because the arguments object isn’t an array. It’s an array-like iterable object.

All we can do is loop through it by its entry using the for loop by its index as we do in the following code:

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}

As we can see, the arguments object has a length property, so we can loop through the entries by its index by using the brackets notation as we do with arrays.

We can also loop through with the for...of loop since it’s an array-like iterable object. Therefore, we can write the following code:

function foo() {
  for (const a of arguments) {
    console.log(a);
  }
}

However, we can’t do anything with it that an array can do like calling the map or filter method on it.

Most likewise, we’ve to convert the arguments object to an array so we can do something with it. If we want to convert it to an array, then we have to do extra work to convert it to an array so that we can do more with it.

To do that we’ve to call the slice method on an empty and then convert the this that we used in slice to the arguuments object so that it’ll return an array.

For instance, we can write the following code to convert the arguments object to an array:

function foo() {
  const args = [].slice.call(arguments, 0);
  console.log(args);
}

In the code above, we converted the arguments object into an array by calling the array prototype’s slice method with the this value set as arguments so that it’ll return an array.

This works because the slice method loops through the array to do the slicing. As we can see, we can loop through the argument object with a regular loop since it has a length property and we can access its values by its index.

We can also write the following instead of what we have in the previous example:

function foo() {
  const args = Array.prototype.slice.call(arguments, 0);
  console.log(args);
}

It does the same thing in that it calls the slice array instance method, but using call to change the this inside the slice method to the arguments object.

If we come back to modern times, we can also use the spread operator to convert the arguments object into an array as follows:

function foo() {
  const args = [...arguments];
  console.log(args);
}

Conclusion

Rest parameters is a useful feature in modern JavaScript. It lets us get the arguments of a function as an array. It’s much better than the old way with the arguments object since it only works with traditional functions and we’ve to do work to convert it to an array.

The post JavaScript Best Practices — Rest Operator appeared first on The Web Dev.

Top comments (3)

Collapse
 
wulymammoth profile image
David • Edited

Nice post, John, but sorry for being a bit pedantic -- this is syntax and the idea is best known as "rest parameters" (not to be confused with REST) according to MDN.

One example that often isn't shown that I'd like to share is in the use of recursive operations:

function headOperation(arr, operation) {
  if (arr.length === 0) return; // base case (empty array) - terminate
  const [head, ...tail] = arr;
  operation(head);
  headOperation(tail); // operate on rest of list (tail)
}
Collapse
 
aumayeung profile image
John Au-Yeung

I think it's a great use of the rest syntax.

Anything is better than using arguments to get the arguments.

Collapse
 
wulymammoth profile image
David

Not necessary in JS, but this is very common in functional programming languages where loops constructs don't exist but all recursive calls are TCO (tail-call optimized)