Javascript中无序的函数参数

Unordered function arguments in Javascript

本文关键字:函数 参数 无序 Javascript      更新时间:2023-09-26

下面是一个带有命名参数的正则函数:

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()等函数每次都会遍历所有参数,以在指定位置按类型查找参数。我只能在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();

我发现使用对象在未来更直接、更不容易出错:

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.');
}

这样,当你几年后回来时,你就不必查看年龄是第一个、第二个还是第五个数字,也更能描述你想要实现的目标。

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

您可以在参数数组中缓存特定类型的参数。这是一个大破解,您可以使用其他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中的内爆函数,由于历史原因,它在文档页面上被标记为一个大黑客。所以我不会这么做。如果顺序太混乱,我会使用WSkid所建议的获取文本对象的方法。

您可以尝试将参数数组复制到可以破坏性更新的东西中:

未经测试的代码: 编辑:我认为它现在可以工作了。

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(,因为你每次都要遍历数组。然而,除非函数可以接收数百个参数,否则这不应该是一个问题。

我同意格里芬的观点。这是不可能做到的,除非你限制了更多的选择。实际上,您有一个字符串、一个布尔值和两个数字。如果没有更多关于什么可以处于什么位置的规则,你就无法判断哪个数字是哪个。如果你愿意制定一些规则,关于哪个数字在前,或者哪个数字在其他争论之后,那么你可以把它整理出来。总的来说,我认为这是个坏主意。使用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});
function who({name, age, isMale, weight}) 
{
    alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.'); 
}
who({name:'Jack', age:30, isMale:true, weight90});

将参数作为对象,可以按任何顺序传递参数。

由于您有相同类型的参数,因此无法做到这一点。

除非年龄和体重有不重叠的范围,否则你不能这样做。根据体重或年龄,你应该如何区分30岁和60岁??

此代码:

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解决方案。