【问题标题】:Javascript convention for variable length arguments可变长度参数的 Javascript 约定
【发布时间】:2023-03-21 16:21:01
【问题描述】:

我对 javascript 开发有了更多的了解,并希望确保我遵循流行的约定。 目前,我有一个库,其中包含可以传递给 1 个模型或多个模型的函数。

鉴于一些 javascript 库非常流行,我很好奇;我是否会通过实现我的“单项或列表”要求、枚举参数变量或允许其中一个参数成为数组来符合“事实上的标准”?

场景 1:参数枚举

// passing a single entity to my function
sendMail( email, recipient1 );

// passing multiple entities to my function
sendMail( email, recipient1, recipient2 );

场景 2:实体参数要么是单个实例,要么是数组

// pass a single entity
sendMail( email, recipient1 );

// passing multiple entities
sendMail( email, [recipient1, recipient2] );

我已经看到使用“场景 2”的 jQuery 领域,但我仍然想问 - 哪种方法最流行,为什么?

谢谢

[编辑]

一些 cmets 遵循相同的思路,使用参数对象 - 类似于“场景 2” - 但我觉得它引入了不必要的复杂性 - 不需要命名元素,因为它们只是一个变量长度列表。我想我会在这里补充一下,以防我的问题不够清楚。

[编辑]

我通过 jQuery-1-7.js 看到这样的代码

queue: function( elem, type, data ) {
    var q;
    if ( elem ) {
        type = ( type || "fx" ) + "queue";
        q = jQuery._data( elem, type );

        // Speed up dequeue by getting out quickly if this is just a lookup
        if ( data ) {
            if ( !q || jQuery.isArray(data) ) {
                q = jQuery._data( elem, type, jQuery.makeArray(data) );
            } else {
                q.push( data );
            }
        }
        return q || [];
    }
}

[编辑]

在与 JP 讨论后,我想出了这个 - 我并不是说这是正确的选择,但它非常灵活......

lastArgumentAsParams: function()
{
    var callerArgs = jQuery.makeArray(this.lastArgumentAsParams.caller.arguments);

    // return empty set if caller has no arguments
    if ( callerArgs.length == 0 )
        return [];
     callerArgs.splice(0, callerArgs.length - 1)
    // remove all but the last argument
    if ( callerArgs.length == 1 && jQuery.isArray(callerArgs[0]))
        return callerArgs[0];
    else
        return callerArgs;
}

如果您在任何函数的开头调用此函数 - 它会将调用者中的最后一个 arg 视为“可变长度参数” - 支持任何约定。

比如我可以这样用

function sendEmail( body, recipients )
{
    recipients = lastArgumentAsParams();

    // foreach( recipient in recipients )...
}

现在,我可以通过以下任何一种方式调用“sendEmail”,它会按预期工作

sendEmail('hello world', "bill@microsoft.com" );
sendEmail('hello world', "bill@microsoft.com", "steve@apple.com" );
sendEmail('hello world', ["bill@microsoft.com", "steve@apple.com"] );

【问题讨论】:

  • 注意:再次强调:您所说的“参数对象”与我的回答和 Uzi 的回答都不同。
  • 我已经编辑了我的答案,希望能消除困惑。
  • 如果我们不将命名对象模式与可变长度列表混淆,我会更喜欢。可变长度列表让我想到了诸如 printf 之类的东西,它可以接受任意数量的参数,而关键字参数非常适合可选参数和可以更改顺序的参数。无论如何,如果 JS 像 Python 一样,你可以混合和匹配两种风格,那可能是最好的。
  • @missingno - 我完全同意,这两者是完全不同的概念。我将命名对象视为“可选参数”,其中每个参数都由函数代码显式引用,可以是不同的类型,并且具有完全不同的语义。可变长度列表通常由函数代码通过某种循环引用,其中每个项目都应共享相同的基本模式,并且在语义上被视为相同。

标签: javascript coding-style


【解决方案1】:

我个人更喜欢使用对象字面量作为参数来支持命名参数,如下所示:

var myfunc = function(params){ //same as: function myfunc(params){....
  alert(params.firstName);
  alert(params.lastName);   
};

myfunc({firstName: 'JP', lastName: 'Richardson'});

我认为它使代码非常可读并且顺序无关紧要。

或

您还可以访问arguments 对象。请注意,它不是数组,而是“类数组”。你可以在这里阅读:http://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/

编辑:

你这里好像有误会。您正在使用短语“arguments object”并且认为它与对象文字表示法相同。他们不是。

arguments 对象允许您这样做:

function myfunc(){
  alert(arguments[0]); //JP
  alert(arguments[1]); //Richardson 
}

myfunc('JP', 'Richardson');

这有帮助吗?

【讨论】:

  • 感谢 JP - 但参数对象没有意义,因为我不想传递“项目的灵活结构,其中每个项目都有不同的语义上下文”。每个“变量项”具有相同的含义。即允许“mailServer.send(email1);”和“mailServer.send(email1, email2);”但我猜你可能更喜欢我的“场景 2”。
  • @Adam 注意arguments 对象和对象字面量是正交概念。如果有一个参数,那么我不会使用对象字面量。如果有多个参数,大多数时候,我更喜欢对象字面量。 100% 清楚,我不喜欢你的“场景 2”。
  • 另外,您的方案 2 不是必需的。因为你可以声明一个没有任何参数的函数并传递任意数量的参数。在arguments 对象上查看我的链接。
  • 谢谢JP。我同意这一点。我来自 C# 背景,所以场景 1 对我来说最有意义 - 但后来我看到后者在 jQuery 中使用......说需要发送多个参数,并且它们都具有相同的语义含义(即我的问题中的情况) - 那么对象文字肯定会妨碍您,因为您必须给每个文字属性一个唯一的名称?我想可以使用:myfunc({0: 'Johnson', 1: 'Richardson'}); // note how they are both last-name - that is intentional 但这不是不必要的冗长吗?数组会自动添加“0”和“1”。
  • “另外,您的方案 2 不是必需的”当然!这正是我的想法——但我已经看到它在 jQuery 代码中是这样做的。我想确保无论我采取什么方式,对于了解最新普遍接受的 javascript 约定的开发人员来说都是有意义的......
【解决方案2】:

另一种常见的方式是使用对象字面量作为变量:

myFunction(true, {option: value, option2: value});

我个人更喜欢这种方法,因为它更冗长,并且使用 javascript 松散类型,它可以更好地提示你这个变量是什么,并且忽略顺序。

Backbone.js 将其用作首选方法。

【讨论】:

  • 谢谢 Uzi - 你的回答似乎和 JP 的一样 - 你不认为这种方法引入了不必要的复杂性吗?调用者和被调用者都需要知道需要使用命名约定'option1:X,option2:Y'。使用 var-args 或数组 ([]) 无需“命名”每个条目。
  • 我不确定它如何宣传复杂性。如果您以与声明变量类型相同的方式考虑它,那么它不会增加太多复杂性,并且会增加很多冗长,这可能是处理松散类型语言的问题。
【解决方案3】:

为了扩展其他答案,我通常会看到两种主要的替代方案:可选参数和关键字参数。我不记得看到任何“使用数组”习语的好例子,考虑到arguments 数组总是可用的,它有点过时了。

无论如何,我的经验法则是。

  • 如果我有很多参数,或者参数列表可能会改变,或者如果参数没有良好的自然顺序,使用命名参数模式

    我最喜欢这种风格的部分是它非常灵活且面向未来,同时也是一种自我记录(以 smalltalk 风格)。

    foo({x1:'1', x2:'2', x3:'3'});
    
    function foo(kwargs){
        //I try to always copy the arguments back into variables.
        //Its a little verbose but it helps documentation a lot and also
        // lets me mutate the variables if I want to
    
        var x1 = kwargs.x1,
            x2 = kwargs.x2,
            x3 = kwargs.x3;
    }
    
  • 如果我的参数很少,不太可能改变,并且它们有一个自然的顺序,使用普通函数(可选参数在最后)

    foo(x1, x2);
    foo(x1, x2, x3);
    

    我现在可以想到如何处理函数中的可选参数的三种主要变体:

    var foo = function(x1, x2, x3){
    
         //variation 1: truthy/falsy
         // Short, but I tend to only use it when the variable stands
         // for an object or other always-truthy kind of value
         x3 = x3 || 'default_value';
    
         //variation 2: using a special placeholder value for blank arguments.
         // Usually this is null or undefined. (and undefined works if the arg is not passed too)
         if(typeof x3 === 'undefined'){ x3 = 'default_value'; }
    
         //variation 3: explicitly check the number of arguments
         // I really like this one since it makes clear if the argument was passed or not.
         if(arguments.length < 3){ x3 = 'default_value'; }
    }
    

另外,有些事情我会尽量避免:

  • 没有具有接收大型参数列表的函数。如果它们开始变得可选并且您忘记了顺序,它可能会变得一团糟

    foo(1, 2, null, null, 3, null, null); //ugh
    
  • 不要使用固定长度的数组会很棘手。它们是多余的,根本没有数组,当我看到一个数组时,我通常希望它 1) 是同质的,2) 可以尽可能长

    foo(true, [1, 2]); //should be foo(true, 1, 2)
    

【讨论】:

    猜你喜欢
    • 2017-02-06
    • 2011-06-02
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 2012-12-25
    相关资源
    最近更新 更多