Соглашение Javascript для аргументов переменной длины - PullRequest
9 голосов
/ 07 марта 2012

Я больше разбираюсь в разработке javascript и хочу убедиться, что я следую популярным соглашениям. В настоящее время у меня есть библиотека, которая состоит из функций, которым можно передать либо одну модель для работы, либо множество моделей.

Учитывая, что несколько библиотек javascript очень популярны, мне любопытно; я бы соответствовал «стандарту де-факто», выполнив мое требование «один элемент или список», перечислив переменную arguments или позволив одному из аргументов быть массивом?

Сценарий 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] );

Я видел области jQuery, в которых используется «сценарий 2», но я все же хотел бы спросить - какой подход наиболее популярен и почему?

Спасибо

[EDIT]

Несколько комментариев следовали тому же принципу использования объекта аргументов - который похож на «сценарий 2» - но я чувствую, что он вносит ненужную сложность - элементы не нужно называть по именам, потому что они просто переменные длина списка. Я подумал, что просто добавлю это здесь, если мой вопрос не был достаточно ясен.

[EDIT]

Я вижу такой код через 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 || [];
    }
}

[EDIT]

После некоторого обсуждения с 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;
}

Если вы вызываете эту функцию в начале любой функции - она ​​будет обрабатывать последний аргумент в вызывающей стороне как «аргумент переменной длины» - поддерживая любое из соглашений.

Например, я могу использовать это так

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"] );

Ответы [ 3 ]

7 голосов
/ 07 марта 2012

Я лично предпочитаю использовать объектные литералы для аргументов для поддержки именованных параметров, например:

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 позволяет вам сделать это:

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

myfunc('JP', 'Richardson');

Помогает ли это?

2 голосов
/ 07 марта 2012

Чтобы расширить другие ответы, я обычно вижу две основные альтернативы: необязательные аргументы и ключевые аргументы. Я не помню, чтобы я видел хорошие примеры использования «массива», и он устарел, учитывая, что массив 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)
    
2 голосов
/ 07 марта 2012

Другой распространенный способ - использовать литерал объекта в качестве переменных:

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

Лично я предпочитаю этот метод, потому что он более многословный, а в случае свободных типов javascript он лучше подсказывает, что это за переменные, и игнорирует порядок.

Backbone.js использует это как предпочтительный метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...