2012-03-06 18 views
8

Estoy obteniendo más en el desarrollo de Javascript y quiero asegurarme de estar siguiendo las convenciones populares. Actualmente tengo una biblioteca que consta de funciones que se pueden pasar ya sea para 1 modelo para operar, o para muchos modelos.Convención de Javascript para argumentos de longitud variable

Dado el clima que algunas bibliotecas de JavaScript son muy populares, tengo curiosidad; ¿estaría cumpliendo con el 'estándar de facto' al lograr mi requisito de 'elemento único o lista de', enumerando la variable de argumentos, o permitiendo que uno de los argumentos sea una matriz?

Escenario 1: argumento enumeración

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

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

Escenario 2: argumento entidad está ya sea sola instancia, o la matriz de

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

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

he visto áreas de jQuery que utilizan 'escenario 2 ', pero aún me gustaría preguntar: ¿qué enfoque es el más popular y por qué?

Gracias

[EDIT]

Un par de comentarios han seguido el mismo orden de ideas, de utilizar un objeto arguments - que es similar a 'el escenario 2' - pero siento que introduce una complejidad innecesaria - el los elementos no necesitan ser nombrados, porque son solo una lista de longitud variable. Pensé que solo agregaría eso aquí en caso de que mi pregunta no fuera lo suficientemente clara.

[EDIT]

veo código como este a lo largo de 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]

Tras un breve debate con JP, me ocurrió con esta - lo que no digo es la elección correcta, pero es muy flexible ...

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

Si llama esto función al comienzo de cualquier función - tratará la última arg en la persona que llama como un 'argumento de longitud variable' - soportará cualquiera de las convenciones.

Por ejemplo, puede utilizar de esta manera

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

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

Ahora, puedo llamar 'sendEmail' en cualquiera de las siguientes maneras y funcionará como se espera

sendEmail('hello world', "[email protected]"); 
sendEmail('hello world', "[email protected]", "[email protected]"); 
sendEmail('hello world', ["[email protected]", "[email protected]"]); 
+0

Nota: una vez más: la "objeto de argumentos" como dices, es diferente tanto de mi respuesta como de la de Uzi. –

+0

He editado mi respuesta para aclarar la confusión. –

+0

Preferiría que no confundiéramos el patrón del objeto nombrado con las listas de longitud variable. Las listas de longitud variable me hacen pensar en cosas como printf, que puede tomar cualquier cantidad de argumentos, mientras que los argumentos de palabra clave son geniales para argumentos opcionales y argumentos que pueden cambiar el orden. De todos modos, probablemente sería mejor si JS fuera como Python, donde puedes mezclar y combinar los dos estilos. – hugomg

Respuesta

7

personalmente prefiero utilizando objetos literales argumentos que pudieran apoyar params con nombre, así:

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

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

creo que hace que el código sea muy legible y el orden no importará.

O

También puede acceder al objeto arguments.Tenga en cuenta que no es una matriz, sino que es "similar a una matriz". Usted puede leer sobre ello aquí: http://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/

Editar:

Usted parece tener un malentendido. Está utilizando la frase "objeto de argumentos" y está pensando que es lo mismo que la notación literal de objetos. Ellos no son.

El objeto arguments le permite hacer esto:

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

myfunc('JP', 'Richardson'); 

ayuda eso?

+0

Gracias JP, pero un objeto de argumentos no tendría sentido, porque no quiero pasar una 'estructura flexible de elementos, donde cada elemento tiene una diferencia de contexto semántico'. Cada 'elemento variable' tiene el mismo significado. es decir, permitir tanto "mailServer.send (email1);" y "mailServer.send (email1, email2);" Pero supongo que probablemente prefiera mi 'escenario 2'. – Adam

+0

@Adam Note el argumento 'arguments' y los literales de objeto son conceptos ortogonales. Si hubiera un parámetro, entonces no usaría literales de objeto. Si hay más de un parámetro, la mayoría de las veces, prefiero los literales de objeto. Para ser 100% claro, no soy un fan de tu "escenario 2". –

+0

Además, su escenario 2 no es necesario. Porque puedes declarar una función sin ningún parámetro y pasar tantas como quieras. Ver mi enlace en el objeto 'arguments'. –

2

Otra forma común es utilizar objeto literal como variables:

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

yo personalmente prefiero este método porque es más prolija y con javascript tipos sueltos, que le da una mejor sugerencia para lo que es estas variables e ignora el orden

Backbone.js usa esto como el método preferido.

+0

Gracias Uzi - su respuesta parece ser la misma que la de JP - ¿No cree que este enfoque introduce una complejidad innecesaria? Tanto la persona que llama como la persona que llama deben saber que se debe usar la convención de nomenclatura 'opción1: X, opción2: Y'. El uso de var-args o una matriz ([]) elimina la necesidad de 'nombrar' cada entrada. – Adam

+0

No estoy seguro de cómo es la complejidad de los anuncios. Si lo piensas de la misma forma que declaras un tipo de variable, entonces no agrega demasiada complejidad, y agrega mucha verbosidad, lo que puede ser un problema relacionado con un lenguaje poco tipado. –

2

Para ampliar las otras respuestas, hay dos alternativas principales que suelo ver: argumentos opcionales y argumentos de palabras clave. No recuerdo haber visto ningún buen ejemplo de la expresión "array-using" y está algo obsoleto, dado que la matriz arguments siempre está disponible de todos modos.

De todos modos, mi regla de oro es.

  • Si tengo muchos argumentos, o la lista de argumentos es probable que cambie, o si los argumentos no tienen un buen orden natural, utilizar el patrón de argumentos con nombre

    Mi parte favorita de este estilo es que es muy flexible y a prueba de futuro, a la vez que se autodocumenta (en un estilo de pequeño estilo).

    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; 
    } 
    
  • Si tengo algunos argumentos, que no es probable que cambie, y que tienen un orden natural para ellos, utilizar una función normal (con los argumentos opcionales últimos en el orden)

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

    Hay tres variaciones principales que se me ocurre en este momento de cómo manejar los argumentos opcionales en la función:

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

Además, no lo son cosas que trato de evitar:

  • ¿Todavía no tiene funciones que reciben una gran lista de argumentos. Puede llegar a ser un desastre si empiezan a convertirse opcional y se le olvida el orden

    foo(1, 2, null, null, 3, null, null); //ugh 
    
  • No matrices uso de longitud fija a ser complicado.Ellos son redundantes sin matrices en absoluto y cuando veo una matriz por lo general esperan que 1) sea homogénea y 2) ser capaz de ser tan largo como yo quiero

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