指示函数使用 'arguments' 对象的最清晰方法是什么?



指示函数使用"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.maxArray.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)

那么,以这种方式编写代码有什么好处:

  1. 咖喱太棒了。它允许您从旧函数创建新函数
  2. 不是使用变参数,而是将数组传递给函数。因此,您不需要任何特殊的方式来指示该函数使用arguments
  3. 假设您必须找到一个名为array的数组的和。使用此方法,您只需执行sum(array)。如果使用可变参数,则需要执行add.apply(null, array)
  4. 假设您想找到ab&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

最新更新