Mastering JavaScript Functional Programming
上QQ阅读APP看书,第一时间看更新

Working with arguments

In Chapter 1, Becoming Functional - Several Questions, and Chapter 2, Thinking Functionally - A First Example, we saw some uses of the spread ( ...) operator. However, the most practical usage we'll be making of it, has to do with working with arguments; we'll see some cases of this in Chapter 6, Producing Functions - Higher-Order Functions. Let's review our once() function:

const once = func => {
let done = false;
return (...args) => {
if (!done) {
done = true;
func(...args);
}
};
};

Why are we writing return (...args) => and afterwards func(...args)? The key has to do with the more modern way of handling a variable number (possibly zero) of arguments. How did you manage such kinds of code in older versions of JS? The answer has to do with the arguments object (not an array!) that lets you access the actual arguments passed to the function.

For more on this, read  https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/arguments.

In JS5 and earlier, if we wanted a function to be able to process any number of arguments, we had to write code as follows:

function somethingElse() {
// get arguments and do something
}

function listArguments() {
console.log(arguments);
var myArray = Array.prototype.slice.call(arguments);
console.log(myArray);
somethingElse.apply(null, myArray);
}

listArguments(22, 9, 60);
// (3) [22, 9, 60, callee: function, Symbol(Symbol.iterator): function]
// (3) [22, 9, 60]

The first log shows that arguments is actually an object; the second log corresponds to a simple array. Also, note the complicated way needed to call somethingElse(), which requires using .apply()

What would be the equivalent code in ES8? The answer is much shorter, and that's why we'll be seeing several examples of usage of the spread operator throughout the text:

function listArguments2(...args) {
console.log(args);
somethingElse(...args);
}

listArguments2(12, 4, 56);
// (3) [12, 4, 56]

The points to remember are:

  • By writing listArguments2(...args) we immediately and clearly express that our new function receives several (possibly zero) arguments.
  • You need not do anything to get an array. The console log shows that args is really an array without any further ado.
  • Writing somethingElse(...args) is much more clear than the alternative way (using .apply()) that we had to use earlier.

By the way, the arguments object is still available in ES8. If you want to create an array from it, you have two alternative ways of doing so, without having to recur to the Array.prototype.slice.call trick:

  • use the .from() method, and write var myArray=Array.from(arguments)
  • or even more simply, say var myArray=[...arguments], which shows yet another type of usage of the spread operator

When we get to higher-order functions, writing functions that deal with other functions, with a possibly unknown number of parameters, will be commonplace. ES8 provides a much shorter way to do so, and that's why you'll have to get accustomed to this usage; it's worth it!