2010-06-02 34 views
12

Sé muy bien que nulo e indefinido son distintos en JavaScript. Sin embargo, no puedo decidir si uso o no ese hecho cuando mis propias funciones son aprobadas como argumento.Manejando la distinción entre parámetros indefinidos y nulos en JavaScript

O, expresado de una manera diferente, ¿debería myFoo(undefined) devolver lo mismo que myFoo(null)?

O, en otro caso, ya que myBar(1, 2, 3) es (casi) lo mismo que myBar(1, 2, 3, undefined, undefined), debe volver myBar(1, 2, 3, null, null) lo mismo que myBar(1, 2, 3)?

Creo que hay un potencial de confusión en ambos casos y que una biblioteca probablemente debería seguir una convención cuando se maneje nulo/indefinido.

Realmente no estoy pidiendo opiniones personales (así que por favor exprese ésas como comentarios en lugar de respuestas). Pregunto si alguien sabe si hay una mejor práctica a la que se debe apegar cuando se trata de manejar esta distinción. ¡Las referencias a fuentes externas son bienvenidas!

+6

'myBar (1, 2, 3)' no es lo mismo que 'myBar (1, 2, 3, undefined, undefined)': el objeto 'arguments' tendrá una longitud de 3 en el primer caso y 5 en el segundo. –

+0

Ah, buen punto. Entonces supongo que es lo mismo si recibo explícitamente cinco parámetros y los uso ignorando el objeto 'arguments'. – Jakob

Respuesta

11

Yo diría que si bien, la mayoría de las veces, hay poco valor para distinguir entre los dos, los casos donde es, el valor tiende a ser bastante interesante.

Tome, por ejemplo, una función a la que se le puede dar una devolución de llamada. undefined podría indicar que algunos de devolución de llamada por defecto se debe utilizar (como si el parámetro no se especifica), pero null podría indicar que no hay devolución de llamada debe hacerse en absoluto:

function asyncWorker(data, callback, timeout) { 
    if (typeof callback === "undefined") { 
     callback = function() { $("#log").append("<p>Done!</p>"); }; 
    } 

    // ... 

    if (callback) callback(); 
} 

asyncWorker([1, 2, 3]); // default callback, no timeout 
asyncWorker([4, 5, 6], null); // no callback, no timeout 
asyncWorker([7, 8, 9], undefined, 10000); // default callback, 10s timeout 

Por supuesto, false o 0 podrían utilizarse en lugar de null aquí, pero podría no ser el caso en un ejemplo más complejo. Y si su código se beneficia de la complejidad adicional de los parámetros depende completamente de usted.:-)

+0

Usar uno de los valores especiales como "nada" y uno como "predeterminado" seguro es interesante. ¡Gran ejemplo! ¿Este concepto es común en las bibliotecas de JavaScript? (Solo estoy acostumbrado a jQuery, e incluso a eso no he usado mucho). – Jakob

+0

No lo he visto ampliamente utilizado, pero unas horas después de escribir esta respuesta, tuve ocasión de distinguir entre 'null' y' undefined' mismo de esta manera para una biblioteca de eventos que estoy escribiendo en el trabajo que admite jQuery -style parámetros opcionales (p. ej. 'method (parm1 [, parm2], parm3)'. –

+0

¿Desde cuándo los argumentos opcionales se convirtieron en 'jQuery-style'? =) –

0

Depende totalmente de usted la forma en que maneja los argumentos transmitidos a su función, por lo que depende de usted. Si desea comprobar si un argumento es null que utilizan

if (myVar === null) { 

y si desea comprobar si un argumento es undefined que utilizan

if (typeof myVar === "undefined") { 

Si el argumento esperado es distinto de 0, nulo o no definido, entonces se puede comprobar esto utilizando

if (myVar) { 

Así que si su myFoo(null) debe comportarse de la misma manera que myFoo(undefined) depende totalmente de cómo maneja estos internamente.

Cuando se trata de parámetros adicionales, esto no tiene otro efecto que el de la colección arguments que es más grande de lo esperado.

+0

I * sospecho * que una comparación con 'null' es (ligeramente) más rápida que una comparación con la cadena' "undefined" '. –

+0

@Marcel ¿Y tu punto es? ¿Que comparar una manzana con una manzana es más rápido que comparar una naranja con una naranja? ¿O que el tipo de llamada lleva más tiempo? ¿De qué importancia es esto? –

+0

Desde el punto de vista de la máquina, hacer 'typeof' que da como resultado una cadena y comparar una cadena con una cadena es más rápido que comparar algo con' null' (en lenguaje ensamblador la mayoría de los procesadores tienen un código de operación 'JZ'). El OP pidió diferencias. –

2

Las mejores prácticas para la manipulación de argumentos

  • definir los argumentos esperados, lo que van a ser usados ​​para, y los tipos de estos
  • decidir cómo se accede a ellos, ya sea a través los argumentos formales, oa través de la colección arguments
  • definen si los valores fuera del rango esperado deberían dar como resultado valores predeterminados
  • verificar que los argumentos están dentro del rango antes de procesar
  • para valores booleanos, deciden si tienen que ser booleanos verdaderos, o solamente Truthy/Falsy

Paso 2, 3 y 4 es de la mayor importancia a que, en este caso

Cómo acceder a los argumentos
esto es algo que tendrá que seleccionar en base a lo que que hace el método, y su str estrategia para manejar una cantidad variable de argumentos.

dar esto por ejemplo

function foo() { 
    var args = arguments.length == 1 ? 
     [document.body].concat([arguments[0]]) : 
     Array.prototype.slice.call(arguments); 

    args[0].style.backgroundColor = args[1]; 
} 

foo(document.body, "red"); 
foo("blue");​ 

true Booleano o Truthy/Falsy
Cómo comprobar valores depende en gran medida de su código está configurado

function foo(elem, color) { 
    if (!color) { // the correct test here should be 'typeof color == "undefined"' 
     color = "green"; 
    } 
    elem.style.backgroundColor = color; 
} 

foo(document.body, "red"); //set the background color to red 
foo(document.body); //set the background color to the default green 
foo(document.body, "");​ //remove the background color !This will fail! 

El último estado de cuenta use incorrectamente el valor predeterminado en lugar del proporcionado, aunque el proporcionado esté dentro del rango esperado.

Cuando se trata de manejar undefined valores de recordar que no hay diferencia en foo(undefined); y foo();excepto que la longitud de la colección arguments será diferente. Cómo se maneja esto (y si es necesario) depende de cómo se accede a los argumentos.

Cuestiones relacionadas