An introduction to ES6 Part 4: Parameters and Spread

By: James Allardice

Tags:

  • es6
  • javascript

This is part 4 of a 10-part series of articles introducting you to some of the features of the upcoming ES6 specification. It may be helpful to start at the first part if you missed it.

Default Parameters

This is a nice little addition to ES6 that makes it much easier to handle a pattern commonly seen in current JavaScript code:

function multiply(x, y) {
    y = y || 1; // Default to 1 if falsy
    return x * y;
}

In that example the y parameter will be set to 1 if no argument is provided (in this case it will actually be set to 1 if the argument provided evaluates to false, but it’s a common enough pattern that we can ignore that fact for the sake of this example). To save us from having to write that extra line of code in the function body, ES6 lets us set default parameter values in the function signature:

function multiply(x, y = 1) {
    return x * y;
}

Parameter defaults are evaluated in the scope of the callee. This means its possible to reference variables declared in outer scopes, and even possible to reference arguments to the left of the one in question:

(function example(x, y = x * 2) {
    console.log(x, y); // 2, 4
}(2));

Note that default parameters do not affect the length of the function. The multiply function in the previous example has a length of 1, compared to 2 in the non-ES6 version.

Rest Parameters

Rest parameters are another small addition designed to remove the additional code needed for another common ES5 pattern: variable numbers of function arguments:

function logEach() {
    var things = Array.prototype.slice.call(arguments);
    things.forEach(function (thing) {
        console.log(thing);
    });
}
logEach("a", "b", "c");

In that example we have to convert the arguments object to a real array before we can iterate over it. The introduction of rest parameters allows us to specify a trailing formal parameter that will collect all arguments from its index onwards into an array (a real array, not an arguments object):

function logEach(...things) {
    things.forEach(function (thing) {
        console.log(thing);
    });
}
logEach("a", "b", "c");

Note that a function signature may only include a single rest parameter, and it must be the final formal parameter to that function. Breaking either of those restrictions will cause a syntax error.

Spread

The ... construct we saw above for rest parameters is reused in ES6 to provide “spread” for both function calls and array literals. In the case of function calls this allows us to avoid the common practice of using the apply method to spread the values of an array across the parameters of the function:

function example(a, b, c) {
    console.log(a, b, c); // 1, 2, 3
}
var args = [1, 2, 3];
example.apply(null, args);

The spread construct allows us to avoid this use of apply (which is good, since the main use of apply is to invoke a function in a particular context):

function example(a, b, c) {
    console.log(a, b, c); // 1, 2, 3
}
var args = [1, 2, 3];
example(...args);

The same syntax can be used with array literals, making them far easier to manipulate than in ES5. To borrow an example from MDN:

var parts = ["shoulder", "knees"];
var lyrics = ["head", ...parts, "and", "toes"];

That example places the values of the first array into the second. In ES5 that would only be possible with a combination of Array methods. This same technique can also be used to easily convert array-like objects into real arrays (think node lists and arguments objects). Previously (as shown in one of the snippets in the Rest Parameters section above) this required a call to (usually) the Array.prototype.slice method. In ES6 it’s much simpler:

var elems = document.querySelectorAll(".myClass");
var arr = [...elems];

Come back soon for the next part, in which we will take a look at how to encapsulate our ES6 code with classes and modules. Follow us on twitter to be notified when it’s posted, and don’t forget we’re hiring


About the Author

James Allardice

James Allardice is a Senior JavaScript Developer at Venntro. He is passionate about clean, maintainable JavaScript and is regularly on the lookout for ways to improve the JavaScript development process. He's currently interested in JSHint, Grunt, AngularJS and ECMAScript6.