指示函数使用"arguments"对象的最佳方式是什么
这显然是基于意见的,但有什么惯例吗?什么时候使用参数数组更好?
一些例子:
// 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)
我从不在JavaScript中使用可变参数。有许多更好的方法来构建代码。例如,我会将您的代码重写如下:
[1,2,3,4,5].forEach(log); // instead of manyArgs(1,2,3,4,5);
function log(a) {
console.log(a);
}
它清晰简洁。
另一个例子是,如果你想在JavaScript中找到一个数字列表的总和:
[1,2,3,4,5].reduce(add, 0); // instead of add(1,2,3,4,5);
function add(a, b) {
return a + b;
}
有太多有用的抽象可用于构建代码,我根本看不到使用可变参数的好处。
然而,我确实使用arguments
对象作为默认值:
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
}
因此,我给你的建议是,根本不要使用各种各样的论点。为代码找到更好的抽象。在我用JavaScript编程的8年里,我从未遇到过使用可变参数的必要性。
编辑:我主张使用更实用的方法来编写代码。我们可以使用currying来使代码更加简洁:
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);
};
}
使用curry
,我们可以将总和示例重写如下:
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;
}
类似地,对于Math.max
和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])
至于Array.prototype.push
,因为它改变了输入数组而不是创建新的数组,所以我更喜欢使用array.concat([element])
而不是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)
那么,以这种方式编写代码有什么好处:
- 咖喱太棒了。它允许您从旧函数创建新函数
- 不是使用变参数,而是将数组传递给函数。因此,您不需要任何特殊的方式来指示该函数使用
arguments
- 假设您必须找到一个名为
array
的数组的和。使用此方法,您只需执行sum(array)
。如果使用可变参数,则需要执行add.apply(null, array)
- 假设您想找到
a
、b
&c
。与add(a, b, c)
相比,您所需要做的只是sum([a,b,c])
。你需要加上额外的[]
括号。但是这样做会使代码更易于理解。根据python的zen“显性比隐性好"
所以这些就是我从不在程序中使用变参数的一些原因。
// Using ES6 syntax ...
var foo = function(/*...args*/){
// shim Array.from, then
var args = Array.from(arguments);
// or
var args = [].slice.call(arguments);
};
最清晰的方法是使用ES6、CoffeeScript(它们被称为"splats",三个点位于标识符之后)和TypeScript(它们被称作"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]);
}
当然,如果你在一个可以使用它们的环境中。它既能更好地进行自我记录,又避免了不得不使用arguments
。