.

Tags:

We have seen how a rest parameter can help the handling of a variable number of function arguments. What about the other way around? Can we turn an array into a series of function arguments? Apparently, ECMAScript 6 defines a new type of operator called the spread operator which does exactly that.

Let us review again our previous example with a supplier truck and a grocery store. Assuming the API of the store accepts a variable number of items for a particular category:

store.add('fruit', 'apple');
store.add('dairy', 'milk', 'cheese', 'yoghurt');
store.add('pastries', 'donuts', 'croissants');

We assume that these delicious items are stored in some boxes, each box happens to be an array:

var dairyBox = ['milk', 'cheese', 'yoghurt'];

A possible solution (out of many others) to invoke store’s add function with the items in the above array is by using Function.prototype.apply. Since we need to pass the food category as the first argument, a little bit dancing with Array.concat is necessary:

store.add.apply(store, ['dairy'].concat(dairyBox));

For the untrained eyes, it looks like one of those magical JavaScript incantations.

With ECMAScript 6, this can be simplified by using ... prefix in a spread expression (section 11.2.5, ES6 draft Rev 14).

store.add('dairy', ...dairyBox);

That dairyBox array is simply spread to fill the remaining argument list.

spreadexpression

Obviously, one possibly common place where spreading is always useful is when dealing with arrays. We know that push accepts multiple number of arguments. The implementation of add function originally looks like:

store.add = function(category, ...items) {
  items.forEach(function (item) {
    store.aisle[category].push(item);
  });
};

which can be further shortened to become something like the following fragment. Nifty, isn’t it?

store.add = function(category, ...items) {
  store.aisle[category].push(...items);
};

(This is of course unnecessary if you choose to change the API to simply accept a single array for the items, instead of a rest parameter combined with spreading).

The use of a spread operator can lead to a different way of combining arrays:

var x = [1, 2];
var y = [3, 4];
x.push(...y);  // x is [1, 2, 3, 4]

What other tricks do you have in mind once you have the spread operator ready to abuse?

  • http://rauschma.de/ Axel Rauschmayer

    I like the push() example! Math.min() and Math.max() are other good examples where spread is great. Furthermore, spreading arrays into constructors is really difficult [1], so spread is more than a convenience there.

    [1] http://www.2ality.com/2011/08/spreading.html

    • http://ariya.ofilabs.com/ Ariya Hidayat

      I like the idea with min and max!

  • Jarred

    Nice post! Typo in the shortened push() fragment, should be .push(…items); with 3 dots.

    • http://ariya.ofilabs.com/ Ariya Hidayat

      Fixed. Thanks!

      • Petr Mikota

        I still see that typo: store.aisle[category].push(..items);

  • http://twitter.com/ryanseddon Ryan Seddon

    Turning a NodeList into an actual array is pretty damn elegant.

    var nodes = […document.querySelectorAll(“divs”)];

  • Matthew Kastor

    I never even saw this coming. Thanks for writing.