Javascript中的无序函数参数

时间:2011-08-12 23:44:57

标签: javascript jquery function parameters arguments

下面是一个带有命名参数的常规函数​​:

function who(name, age, isMale, weight)
{
    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}

who('Jack', 30, true, 90); //this is OK.

我想要的是;是否按顺序传递参数;该函数应该产生类似的结果(如果不相同):

who('Jack', 30, true, 90); //should produce the same result with the regular function
who(30, 90, true, 'Jack'); //should produce the same result
who(true, 30, 'Jack', 90); //should produce the same result

这使您能够以任何顺序传递参数列表,但仍将映射到逻辑顺序。我到目前为止的做法是这样的:

function who()
{
    var name = getStringInArgs(arguments, 0); //gets first string in arguments
    var isMale = getBooleanInArgs(arguments, 0); //gets first boolean in arguments
    var age = getNumberInArgs(arguments, 0); //gets first number in arguments
    var weight = getNumberInArgs(arguments, 1); //gets second number in arguments

    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.');
}

这里有一点问题; getStringInArgs()getNumberInArgs()等函数每次都会遍历所有参数,以便在指定位置找到类型的arg。我可以只遍历args一次并保留位置的标志但是我必须在who()函数内部进行。

您认为这种方法是合乎逻辑的吗?有没有更好的方法呢?

编辑1:以上代码实际上有效。我只是想知道是否有更好的方法。

编辑2 :您可能想知道这是否必要或是否有意义。主要原因是:我正在编写一个jQuery函数,它为DOM元素添加了一个特定的样式。我希望此函数将其参数视为速记CSS值。

示例:

border: 1px solid red;
border: solid 1px red; /*will produce the same*/

因此;这是现在的真实和最终代码:

(function($){
function getArgument(args, type, occurrence, defaultValue)
{
    if (args.length == 0) return defaultValue;

    var count = 0;
    for(var i = 0; i < args.length; i++)
    {
          if (typeof args[i] === type)
          {
              if (count == occurrence) { return args[i]; }
              else { count++; }
          }
    }
    return defaultValue;
}

$.fn.shadow = function()
{
    var blur = getArgument(arguments, 'number', 0, 3);
    var hLength = getArgument(arguments, 'number', 1, 0);
    var vLength = getArgument(arguments, 'number', 2, 0);
    var color = getArgument(arguments, 'string', 0, '#000');
    var inset = getArgument(arguments, 'boolean', 0, false);
    var strInset = inset ? 'inset ' : '';

    var sValue = strInset + hLength + 'px ' + vLength + 'px ' + blur + 'px ' + color;
    var style = {
        '-moz-box-shadow': sValue,
        '-webkit-box-shadow': sValue,
        'box-shadow': sValue
    };

    return this.each(function()
    {
        $(this).css(style);
    });
}
})(jQuery);

用法

$('.dropShadow').shadow(true, 3, 3, 5, '#FF0000');
$('.dropShadow').shadow(3, 3, 5, '#FF0000', true);
$('.dropShadow').shadow();

8 个答案:

答案 0 :(得分:5)

我发现将来使用对象更直接,更不容易出错:

var person = {
 name: 'Jack',
 age: 30,
 isMale: true,
 weight: 90
};

who(person);

function who(person){
 alert(person.name + 
  ' (' + (person.isMale ? 'male' : 'female') + '), ' + 
  person.age + ' years old, ' +
  person.weight + ' kg.');
}

这样,当你多年后回来时,你不必查找年龄是第一个,第二个还是第五个数字,并且更能描述你想要实现的目标。

答案 1 :(得分:2)

这似乎不必要地复杂,不仅仅是从函数的角度来看,它需要重新排序其参数,而且还要从调用者的角度来看。你说该函数可以接受任何顺序的参数,但这并不完全正确。由于您确定哪个变量基于类型,因此它依赖于每个变量是不同的类型。名称和性别可以是任何位置,但数字参数必须按特定顺序排列。它还可以阻止某人传入“30”或“90”,这些数字是数字但会被视为字符串 - 将其与名称混淆并且没有找到年龄或体重。

答案 2 :(得分:1)

您可以在arguments数组中缓存特定类型的参数。这是大黑客,您可以使用与其他getTypeInArgs相同的模式

function getNumberInArgs(args, index) {
    if (!args.numbers) {    
      args.numbers = [];
      for (var i=0; i < args.length; i++) {
        // You have to implement isNumber
        if ( isNumber (args[i]) ) {
          args.numbers.push(args[i];
        }      
      }
    }
    return args.numbers[index];
}

我从来没有听说过以任何顺序接受参数,除了PHP中的implode函数,并且由于历史原因,它在documentation页面上被标记为大黑客。所以我不会这样做。如果订单太混乱,我会按照WSkid的建议使用获取文字对象的方法。

答案 3 :(得分:1)

您可以尝试将arguments数组复制到可以破坏性更新的内容中:

未经测试的代码: 编辑:我认为它现在有效。

function args_getter(their_arguments){
    //copy arguments object into an actual array
    //so we can use array methods on it:
    var arr = Array.prototype.slice.call(their_arguments);

    return function(type){
        var arg;
        for(var i=0; i<arr.length; i++){
            arg = arr[i];
            if(type == typeof arg){
                arr.slice(i, 1);
                return arg;
            }
        }
        return "do some error handling here"
    }
}

function foo(){
    var args = args_getter(arguments);
    var b1 = args('boolean');
    var b2 = args('boolean');
    var n1 = args('number');
    console.log(n1, b1, b2);
}

//all of
// foo(1, true, false),
// foo(true, 1, false), and
// foo(true, false, 1)
// should print (1, true, false)

这仍然是O(N ^ 2),因为每次都要经过数组。但是,除非您的函数可以接收数百个参数,否则这不应成为问题。

答案 4 :(得分:0)

由于你有相同类型的参数,所以你无法做到这一点。

除非年龄和体重不重叠范围,否则您无法执行此操作。你如何区分体重或年龄30到60岁?

答案 5 :(得分:0)

我同意格里芬的观点。除非您限制的选择多于您的选择,否则无法完成此操作。实际上,你有一个字符串,一个布尔值和两个数字。如果没有更多关于什么位置的规则,你就不知道哪个数字是哪个。如果你愿意做一些关于哪个数字首先出现的规则,或者哪个数字出现在其他参数之后,那么你可以对其进行排序。总的来说,我认为这是一个坏主意。使用像WSkid建议的对象要好得多(从良好编程的角度来看)。

无论如何,如果你想制定一个规则,比如重量必须在年龄之后,那么它可以这样做:

function findParm(args, type) {
    for (var i = 0; i < args.length; i++) {
        if (typeof args[i] == type) {
            return(i);
        }
    }
    return(-1);
}

function who(name, age, isMale, weight) {
    // assumes all variables have been passed with the right type
    // age is before weight, but others can be in any order

    var _name, _age, _isMale, _weight, i;

    var args = Array.prototype.slice.call(arguments);
    _name = args[findParm(args, "string")];     // only string parameter
    _isMale = args[findParm(args, "boolean")];  // only boolean parameter
    i = findParm(args, "number");               // first number parameter
    _age = args[i];
    args.splice(i, 1);                          // get rid of first number
    _weight = args[findParm(args, "number")];   // second number parameter

    // you now have the properly ordered parameters in the four local variables
    // _name, _age, _isMale, _weight
}

who("fred", 50, false, 100);

在这个小提琴中工作:http://jsfiddle.net/jfriend00/GP9cW/

我建议更好的编程是这样的:

function who(items) {
    console.log(items.name);
    console.log(items.age);
    console.log(items.weight);
    console.log(items.isMale);
}

who({name: "Ted", age: 52, weight: 100, isMale: true});

答案 6 :(得分:0)

此代码:

function who(items) {    console.log(items.name);    console.log(items.age);    console.log(items.weight);    console.log(items.isMale);}who({name: "Ted", age: 52, weight: 100, isMale: true});

之前发布的帖子似乎很明智。但为什么让事情变得复杂。当人们把事情变得复杂时,我的经历就出错了。

BTW - 上面的解决方案(如之前发布的那样)与Perl解决方案类似。

答案 7 :(得分:0)

function who({name, age, isMale, weight}) 
{
    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.'); 
}

who({name:'Jack', age:30, isMale:true, weight90});

将参数作为对象,允许您以任何顺序传递参数。