Usage of rest parameter and spread operator in javascript

What's the usage of rest parameter that will be added in ECMAScript 6?

For example, in ECMAScript 5 you can do the following to get an array of parameters starting from the second element:

// ES 5
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name) {
  var items = [].slice.call(arguments, 1); //['money'] in first case
  items.forEach(function (item) {
    vault.customer[name].push(item);
  });
}

and that will be equivalent to the following code in ECMAScript 6:

// ES 6
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name, ...items) {
  items.forEach(function (item) {
    vault.customer[name].push(items)
  });
}

Is the difference between them is just syntax or there's a performance issue?

Also for spread operator (...)

//in ecmascript5
var max = Math.max.apply(null, [14, 3, 77]);
//but in ecmascript6
var max = Math.max(...[14, 3, 77]);

Is this just syntax change or performance issue?


Solution 1:

Is the difference between them is just syntax or there's a performance issue?

Both, and more...

Rest parameters:

  1. Are a known idiom in other languages (Ruby, Python).
  2. Are esier to read and maintain (vs. slice).
  3. Are easier to understand for beginners.
  4. Can (and likely will) result in better performance, since engines can optimize.
  5. Are tool friendlier, as they can be analyzed statically.

Solution 2:

In addition to @kangax’s response, I would elaborate that performance and correctness are problematic many times the arguments object is invoked. If you pass the arguments object to another function, you pass with it the right to modify the corresponding local variables in your scope.

function foo(arg) {
    bar(arguments);
    return arg;
}

function bar(args) {
    args[0] = 20;
}

foo(10) // 20

The existence of this feature invalidates local reasoning within a function, which makes JIT optimization more difficult and introduces certain security hazards. Programs that are designed for speed must work around this problem with far more elaborate boilerplate code than the Array.prototype.slice.call(arguments) idiom, and in security contexts, the passing of arguments must be strictly disallowed.

Eliminating the need to use the arguments object to extract variadic arguments is one of the many advantages to the new syntax.

Solution 3:

In your given example, you directly pass the object literal. Whilst still semantic, it seems un-analogous to the application of the spread operator. IMO, the spread operator's value becomes apparent when listing each parameter would determent code readability (and maintainability, when replacing traditional push, splice, concat methods).

With spread operator

let nums = [1.25,5.44,7.15,4.22,6.18,3.11];   

function add(a, b, ...nums){
  let sum = parseInt(a + b);
  nums.forEach(function(num) {
    sum += num;
  })
  return parseInt(sum);
}

console.log(add(1, 2, ...nums)); //30

ES6Fiddle demo (compiled by traceur-compiler)

Without spread operator

var nums = [1.25,5.44,7.15,4.22,6.18,3.11];   

function add(a, b, nums){
  var sum = parseInt(a + b);
  nums.forEach(function(num) {
    sum += num;
  })
  return parseInt(sum);
}

console.log(add(1, 2, nums)); //30

JSFiddle demo

In closing, I don't think that using the spread operator will improve or impede performance, it does however offer improved code readability, and arguably maintainability too. Regrettably, ES6 isn't widely implemented yet, and I'll assertively speculate that it will take sometime for browser support to ensue.

Fun fact: PHP 5.6 introduces similar functionality with its variadic functions which will make func_get_args() redundant.