问题
What's the best way to indicate a function uses the 'arguments' object?
This is obviously opinion based but are there any conventions? When would it be better to use an array of arguments?
Some examples:
// Function takes n arguments and makes them pretty.
function manyArgs() {
for (var i = 0; i < arguments.length; i++)
console.log(arguments[i]);
}
function manyArgs( /* n1 , n2, ... */ )
function manyArgs(n1 /*, n2, ... */ )
function manyArgs(argArray)
回答1:
// Using ES6 syntax ...
var foo = function(/*...args*/){
// shim Array.from, then
var args = Array.from(arguments);
// or
var args = [].slice.call(arguments);
};
回答2:
I never use variadic arguments in JavaScript. There are many better ways of structuring your code. For example, I would rewrite your code as follows:
[1,2,3,4,5].forEach(log); // instead of manyArgs(1,2,3,4,5);
function log(a) {
console.log(a);
}
It's clear and concise.
Another example, if you want to find the sum of a list of numbers in JavaScript:
[1,2,3,4,5].reduce(add, 0); // instead of add(1,2,3,4,5);
function add(a, b) {
return a + b;
}
There are so many useful abstractions available to structure your code that I don't see the benefit of using variadic arguments at all.
I do however use the arguments
object for default values:
function foo(a,b,c) {
switch (arguments.length) {
case 0: a = "default argument for a";
case 1: b = "default argument for b";
case 2: c = "default argument for c";
}
// do something with a, b & c
}
Hence my advise to you would be to not use variadic arguments at all. Find a better abstraction for your code. I've never encountered the need to use variadic arguments in the 8 years that I have been programming in JavaScript.
Edit: I would advocate using a more functional approach to writing code. We can use currying to make code more succinct:
function curry(func, length, args) {
switch (arguments.length) {
case 1: length = func.length;
case 2: args = [];
}
var slice = args.slice;
return function () {
var len = arguments.length;
var a = args.concat(slice.call(arguments));
if (len >= length) return func.apply(this, a);
return curry(func, length - len, a);
};
}
Using curry
we can rewrite the sum example as follows:
var reduce = curry(function (func, acc, a) {
var index = 0, length = a.length;
while (index < length) acc = func(acc, a[index++]);
return acc;
});
var sum = reduce(add, 0);
sum([1,2,3,4,5]); // instead of add(1,2,3,4,5);
function add(a, b) {
return a + b;
}
Similarly for Math.max
and Array.prototype.concat
:
var reduce1 = curry(function (func, a) {
if (a.length === 0)
throw new Error("Reducing empty array.");
return reduce(func, a[0], a.slice(1));
});
var maximum = reduce1(max);
maximum([1,2,3,4,5]); // instead of Math.max(1,2,3,4,5);
function max(a, b) {
return a > b ? a : b;
}
var concat = reduce(function (a, b) {
return a.concat(b);
}, []);
concat([[1,2],[3,4],[5,6]]) // instead of [1,2].concat([3,4],[5,6])
As for Array.prototype.push
, because it mutates the input array instead of creating a new one, I prefer using array.concat([element])
instead of array.push(element)
:
var push = reduce(function (a, e) {
return a.concat([e]);
});
push([1,2,3], [4,5]); // instead of [1,2,3].push(4, 5)
So what are the advantages of writing code this way:
- Currying is awesome. It allows you to create new functions from old ones.
- Instead of using variadic arguments you are passing arrays to functions. So you don't need any special way to indicate that the function uses
arguments
. - Suppose you have to find the sum of an array named
array
. Using this method you just dosum(array)
. If you use variadic arguments then you would need to doadd.apply(null, array)
. - Suppose you want to find the sum of
a
,b
&c
. All you need to do issum([a,b,c])
, as compared toadd(a, b, c)
. You need to put in the extra[]
brackets. However doing so makes your code more understandable. According to the zen of python “explicit is better than implicit”.
So these are some of the reasons I never use variadic arguments in my programs.
回答3:
The clearest way is to use the spread operator available in ES6, CoffeeScript (where they are called "splats" and the three dots come after the identifer), and TypeScript (where they are called "rest parameters").
// Function takes n arguments and makes them pretty.
function manyArgs(...args) {
for (var i = 0; i < args.length; i++)
console.log(args[i]);
}
If you're in an environment where you can use them, of course. It is both better self-documenting, and avoids having to muck around with arguments
.
来源:https://stackoverflow.com/questions/26700711/whats-the-clearest-way-to-indicate-a-function-uses-the-arguments-object