【问题标题】:Unordered function arguments in JavascriptJavascript中的无序函数参数
【发布时间】:2023-03-14 21:48:01
【问题描述】:

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

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();

【问题讨论】:

  • 我认为虽然你有两个数字类型的参数,但你不能这样做。如果每个参数都有不同的类型,这是可能的
  • @Mohsen,这确实有效。多个数字类型参数没有问题。事实上,相同类型的参数是有序的。请查看编辑。

标签: javascript jquery function parameters arguments


【解决方案1】:

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

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

这样,当您多年后回来时,您不必查找年龄是第一个、第二个还是第五个数字,并且更能描述您想要完成的事情。

【讨论】:

  • 你完全正确,但这不是我要找的。我知道我必须清楚地记录这些功能,但这没关系。无论如何,谢谢。
  • @radgar,用这个方法,你可以做你想做的事。
【解决方案2】:

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

【讨论】:

  • 事实上;这就是我将“任何订单”加粗的原因:)我应该再次描述一下;参数实际上映射成逻辑顺序。
  • 我了解您正在尝试做什么,并且您现有的代码有效,我只是不确定为什么。您能否提供一个使用案例,在该案例中这是理想的行为?
  • 我已经在帖子中添加了实际代码以及我需要它的原因。谢谢。
【解决方案3】:

您可以在参数数组中缓存特定类型的参数。这是一个大技巧,您可以使用其他 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 建议的采用文字对象的方法。

【讨论】:

  • 通过编辑,我可以理解您为什么要这样做。但是,我建议的代码仍然可以解决您提到的问题。您不希望 getNumberInArgs 每次都扫描所有参数,也不希望缓存调用函数的结果。我错过了什么吗?
  • 是的,重新扫描问题仍然存在,但正如@missingno 所说;除非函数可以接收数百个参数,否则这可能不是问题。也许我应该将 for 循环限制为预期的参数数量。
  • 顺便说一句,如果使用new Boolean, new String or new Number 创建任何参数,您测试数字、字符串和布尔值的方法将失败
  • +1 :) 感谢您的提醒。似乎typeof 运算符有问题。通过javascriptweblog.wordpress.com/2011/08/08/… 修复它
【解决方案4】:

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

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

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),因为您每次都通过数组。但是,除非您的函数可以接收数百个参数,否则这应该不是问题。

【讨论】:

    【解决方案5】:

    我同意格里芬的观点。除非您对选择的限制超出您的范围,否则这是无法做到的。实际上,您有一个字符串、一个布尔值和两个数字。如果没有更多关于什么可以处于什么位置的规则,你就无法分辨哪个数字是哪个。如果您愿意对哪个数字在前或哪个数字在其他参数之后制定一些规则,那么您可以对其进行排序。总的来说,我认为这是一个坏主意。使用 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});
    

    【讨论】:

    • arguments 不是一个实际的数组,也没有 spice 方法(至少在我的浏览器上......)
    • 只要做var args = Array.prototype.slice.call(arguments, 0),args就是一个与参数内容相同的普通数组,你可以在上面调用所有的数组方法。
    • @Juan Mendes - 我确实这样做了,并修复了代码中的其他一些嘘声。它现在可以在小提琴中使用。
    【解决方案6】:
    function who({name, age, isMale, weight}) 
    {
        alert(name + ' (' + (isMale ? 'male' : 'female') + '), ' + age + ' years old, ' + weight + ' kg.'); 
    }
    
    who({name:'Jack', age:30, isMale:true, weight90});
    

    以参数为对象,可以任意顺序传递参数。

    【讨论】:

      【解决方案7】:

      你无法做到这一点,因为你有相同类型的参数。

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

      【讨论】:

      • 我已经按类型和位置(顺序)区分了它们。也许我不应该在主题中说“无序”,但它可以解释我需要什么。谢谢。
      • 如果你要规定年龄在体重之前,你为什么不只对参数进行排序(像普通函数一样?)。这没有任何意义。
      • 仍然没有意义,因为1px red solid 可以按任何顺序排列。您再次声明只有 some 参数需要按顺序排列,为什么不将它们全部按顺序排列,您实际上使传递参数的问题复杂化了。此外,在您可以设置模糊或阴影的语言中(参见动作脚本 3),参数需要按特定顺序给出 - 这是有原因的!
      • 他试图模仿不需要排序的CSS参数。
      • 我明白你的意思,也许你是对的。 AS3 有过滤器包,它们是带有有序/命名参数的独立类。但是在这里,我实际上是在向一个元素添加 CSS,所以我遵循 CSS 速记值的模式。再说一次,也许不是那么必要。
      【解决方案8】:

      这段代码:

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

      以前发布的帖子似乎是明智的。但是为什么要把事情复杂化。当人们把事情复杂化时,我的经验会出错。

      顺便说一句 - 上面的解决方案(正如之前发布的那样)类似于 Perl 解决方案。

      【讨论】:

        猜你喜欢
        • 2011-09-17
        • 2012-03-09
        • 1970-01-01
        • 2023-04-09
        • 2016-08-18
        • 2022-11-20
        • 1970-01-01
        • 1970-01-01
        • 2015-11-25
        相关资源
        最近更新 更多