Exploring ECMAScript 2015 (ES6): Parameters

ECMAScript 2015 introduces new features for JavaScript's function parameters: default parameters, rest parameters, and the spread operator. These combine to add a lot more flexibility to the function syntax.

Default parameter values is such an intuitive feature, I once forgot JavaScript didn't include it after some time working with other programming languages. To be fair, JavaScript does set a default value for function parameters, but the value is always undefined. Not a whole lot of flexibility there. ES2015 fixes that.

// ES2015
function add(a, b = 3) {  
  return a + b;
}

// ES5
function add(a, b) {  
  b = b || 3;
  return a + b;
}

console.log(add(2)); // 5  
console.log(add(2, 2)); // 4  

The new default parameters allow us to set a practical default for a parameter without resorting to workarounds, and allows us to avoid mutating arguments passed in a function call. The latter is a good practice in general—it can have unintended results—and required if you want to follow the ideals of immutability in functional programming.

Speaking of the weirdness of the arguments object, the new rest parameters feature might make it obsolete. arguments can be confusing for new JavaScript developers. Intuitively, it seems like it should be an array containing all the arguments passed in a function call—it even has an arguments.length property and individual arguments can be accessed with a arguments[0] style index. It is an array-like object, but it is not an array, and it does not have access to array methods.

function getLength() {  
  console.log('arguments.length: ' + arguments.length);
}

getLength('a', 'b', 'c', 'd'); // arguments.length: 4

function logger() {  
  arguments.forEach(arg => {
    console.log(arg);
  })
}

logger('a', 'b', 'c', 'd'); // arguments.forEach is not a function  

Rest parameters allow us to access arguments passed to a function as an actual array.

function logger(...items) {  
  items.forEach(arg => {
    console.log(arg);
  })
}

logger('a', 'b', 'c', 'd'); // a, b, c, d  

Rest parameters also allows us more flexibility when used with named parameters. With arguments you need to account for any named parameters, and skip the indexes containing those values. With rest parameters, it works like it sounds like it would: you get an array of the rest of the arguments passed after the named arguments.

function loggerWithPrefix(prefix, ...items) {  
  items.forEach(arg => {
    console.log(prefix + arg);
  })
}

loggerWithPrefix('log: ', 'a', 'b', 'c', 'd'); // log: a, log: b, log: c, log: d  

The spread operator follows the same ...params pattern as rest parameters, but when calling a function, and for a different purpose. The spread operator allows you to pass an array as an argument in a function call, and have the function spread the items in the array over the function's parameters. Before ES2015, it was common to abuse the Function.prototype.apply() method to achieve the same results.

// ES2015
function sumThree(a, b, c) {  
  return a + b + c;
}

const numCollection = [1, 2, 3];  
sumThree(...numCollection); // 6

// ES5
function sumThree(a, b, c) {  
  return a + b + c;
}

var numCollection = [1, 2, 3];  
sumThree.apply(undefined, numCollection); // 6  

That about wraps it up for changes to function parameters in ECMAScript 2015. Default parameters let us set sensible defaults instead of undefined. Rest parameters allow us access to an array of parameters, and to do away with the broken arguments implementation. The spread operator allows us to pass an array in the place of multiple arguments, and have them spread the items across the parameters. We get a lot more flexibility, and we get to avoid hacky solutions. Seems to be a trend with these ES2015 changes, doesn't it?

Further Reading

Tyler Walters

Written by Tyler Walters

Tyler Walters is a software engineer in Phoenix, Arizona. He is married to a beautiful woman and has three incredible daughters. He is interested in game development, writing, beer, and hot wings.