¿Es mejor devolver `undefined` o` null` desde una función javascript?

98

Tengo una función que he escrito que básicamente se ve así:

function getNextCard(searchTerms) {
  // Setup Some Variables

  // Do a bunch of logic to pick the next card based on termed passed through what I'll call here as 'searchTerms' all of this logic is omitted because it's not important for my question.
  // ...

  // If we find a next card to give, than give it
  if (nextCardFound)
    return nextCardFound;

  // Otherwise - I'm returning undefined
  return undefined;
}

Pregunta: ¿Sería mejor devolver "nulo" aquí?

Puedo devolver lo que quiera, obviamente ... No estaba seguro de qué es lo mejor para usar.

El código que llama a esta función sabe cómo lidiar con undefined (en realidad, nunca sucederá a menos que algo salga terriblemente mal)

La razón por la que hago esta pregunta es que escuché en alguna parte algo que sonaba como "No asigne indefinido a variables" o algo, que hará que sea más difícil de depurar. Entonces, el hecho de que puedo ver que nullse devuelve me dice que la devolución está funcionando, pero básicamente funciona de manera similar a undefined.


Documentación:

Mozilla Docs no respondió mi pregunta ... Google tampoco: \

Esta pregunta SO - era demasiado amplia para lo que estoy tratando de entender aquí.

Jeremy Iglehart
fuente
1
¿No responde esta pregunta SO ?
warkentien2
8
En mi opinión, vuelve null. Deje undefinedJavaScript en sí. Sin embargo, no hay "mejor" por lo que esto es una cuestión de opinión.
Felix Kling
@ warkentien2 Gracias, esto fue útil, pero todavía no tengo claro cuál es la convención aquí para regresar de una función getter.
Jeremy Iglehart
1
Leí nullcomo "no hay un valor apropiado para lo que estás pidiendo" y undefinedcomo "no puedo calcular lo que estás pidiendo".
Marty
@ warkentien2 esa pregunta, y la que vinculé en mi respuesta, están relacionadas, pero ambos parecen estar preguntando cuál es la diferencia entre ellos y no cuándo usar uno u otro como valor de retorno.
chiliNUT

Respuestas:

37

Argumentaré que no existe la mejor manera, e incluso las funciones estándar a veces eligen una u otra.

Por ejemplo:

  • [[Prototipo]]

    Los objetos ordinarios tienen una ranura interna [[Prototype]], que determina de qué otro objeto heredan. Por supuesto, debe haber una forma de decir que un objeto no hereda de ningún otro. En este caso, "no existe tal objeto" se representa usando null.

  • Object.getOwnPropertyDescriptor

    Se espera que devuelva un descriptor de propiedad, es decir, un objeto que describe una propiedad (por ejemplo, valor, capacidad de escritura, enumerabilidad y configurabilidad). Sin embargo, es posible que la propiedad no exista. En este caso, "no existe tal propiedad" se representa mediante undefined.

  • document.getElementById

    Se espera que devuelva el elemento con el ID proporcionado. Sin embargo, es posible que no haya ningún elemento con ese ID. En este caso, "no existe tal elemento" se representa usando null.

Así que elija lo que prefiera o crea que tenga más sentido para su caso específico.

Oriol
fuente
3
después de leer esto , decidí sugerir la void 0técnica para futuros espectadores de esta respuesta. También agregué un código para intentar aclarar tu punto. ¡Gracias por su respuesta!
Jeremy Iglehart
114

Indefinido generalmente se refiere a algo que aún no se ha asignado un valor (todavía). Nulo se refiere a algo que definitivamente no tiene valor. En ese caso, recomendaría devolver un null. Tenga en cuenta que una función sin valor de retorno especificado devuelve implícitamente undefined.

De la especificación ECMAScript2015

4.3.10 valor indefinido

valor primitivo utilizado cuando a una variable no se le ha asignado un valor

4.3.12 valor nulo

valor primitivo que representa la ausencia intencional de cualquier valor de objeto

http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-undefined-type

Otras lecturas:

¿Cuándo se usa nulo o indefinido en JavaScript?

chiliNUT
fuente
1
Sí, indefinido es el valor utilizado cuando a una variable no se le ha asignado un valor. ¿Por qué exactamente eso implica que no debería devolver undefined en una función?
Oriol
1
@Oriol, en mi mente, dado que una función void devuelve undefined, ese es un valor reservado para funciones de ese tipo, de modo que al manejar el valor de retorno de una función, null me dice que decidió devolver null, mientras que undefined me dice o decidió regresar indefinido, o decidió no devolver nada, pero definitivamente no sé cuál. Además, si lo estoy haciendo var x=someFunc();, estoy asignando intencionalmente un valor xa y prefiero que no pase ninguna prueba que indique que no se le ha asignado (o puede que no) un valor. En mi humilde opinión
chiliNUT
Esta debería ser la respuesta aceptada. Así es como se pretendía usar en la especificación
zinc
1
No lo leo de esa manera. Lo leí como: Si define una variable pero no la inicializa, tendrá un valor inicial indefinido. El programador debe usar Null para indicar intencionalmente que una variable está vacía. En mi humilde opinión, undefined nunca debe ser asignado a una variable por el programador, déjelo en manos del motor js para que lo use. El término valor de "objeto" es engañoso, ya que en JS incluso las primitivas se comportan como objetos en su mayor parte debido al autoboxing
chiliNUT
1
Sí, eso tiene sentido. Para ser justos, no me importa usar uno sobre el otro (aunque estoy más acostumbrado a hacerlo null) siempre que se quede con uno, pero tener 2 valores para indicar ausencia de valor (cualquiera que sea el "tipo") siempre es confuso
Sergio Rosas
39

Le daré mi forma personal de elegir entre los dos.

Mi pregunta simple es: ¿ podría el valor, dada otra entrada / estado / contexto, definirse para algo?

Si la respuesta es sí, use nullelse use undefined. De manera más general, cualquier función que devuelva un objeto debería regresar nullcuando el objeto deseado no existe. Porque podría existir dada otra entrada / estado / contexto.

nullrepresenta la ausencia de valor para una entrada / estado / contexto dado. Implícitamente significa que el concepto de valor en sí mismo existe en el contexto de su aplicación, pero puede estar ausente. En su ejemplo, existe el concepto de una tarjeta siguiente, pero es posible que la tarjeta en sí no exista. nulldebería ser usado.

undefinedrepresenta implícitamente la ausencia de significado de ese valor en el contexto de su aplicación. Por ejemplo, si manipulo un userobjeto con un conjunto de propiedades dado e intento acceder a la propiedad pikatchu. El valor de esta propiedad debe establecerse en undefinedporque en mi contexto no tiene ningún sentido tener tal propiedad.

ngryman
fuente
1
Esto me suena tan cierto. En mi opinión, las funciones puras deberían regresar null, mientras que las funciones con efectos secundarios deberían regresar undefined, cuando se piensa como un programador funcional.
Jake
4

undefinedno es algo a lo que deba asignar. Es posible que desee considerar devolver algo diferente a undefined. En su caso, incluso si no devuelve nada, el resultado undefinedya será . Entonces, sugiero ir connull lugar.

Considere esta muestra,

function getSomething() {
     // .. do something
     return undefined;
}

function doSomething() {
     // .. I'm not gonna return anything.
}

var a = getSomething();
var b = doSomething();

El resultado de la muestra anterior a === bes, que es undefined. La diferencia es que guarda 1 ejecución de declaración.

choz
fuente
@Oriol quiero decir, undefinedno tiene que ser asignado. Todas las variables declaradas sin valores ya lo son undefined.
Choz
@choz & @Oriol - como lo mencionó antes @chiliNUT "Tenga en cuenta que una función sin valor de retorno especificado devuelve implícitamente undefined". - esto es cierto porque (function(){ /* code */ })()devuelve nulo en una consola.
Jeremy Iglehart
@JeremyIglehart Ese código en realidad no devuelve nada. Y además, da undefineden mi consola Chrome y Firefox.
Choz
OK, no entendí tu punto. Sí, si no devuelve nada explícitamente, undefined se devolverá implícitamente. Pero, ¿por qué importa eso?
Oriol
1
@Oriol, creo que @choz estaba tratando de decir (como algunos otros también mencionaron en esta pregunta) que si quiero regresar undefinedsi algo más no regresa antes, no lo necesito porque el comportamiento predeterminado de la función es no devuelve nada es devolver indefinido, solo están diciendo que esto no es necesario. Además ... me gusta lo que tienes que decir sobre las funciones getter incorporadas que devuelven nulo. Por favor publique su respuesta a tal efecto y la aceptaré.
Jeremy Iglehart
3

Depende de lo que necesites hacer con el valor devuelto.

typeof null devuelve un objeto. ese objeto tiene un valor de indefinido

tipo de devoluciones indefinidas undefined

Dan
fuente
Personalmente suelo usar null.
Dan
4
"ese objeto tiene un valor indefinido" No, no lo es y no es un objeto, es nulo. typeofno necesariamente devuelve el verdadero tipo de datos de un valor, tiene un mapa que asigna tipos de datos a etiquetas y devuelve la etiqueta correspondiente.
Felix Kling
No confíe typeof, a pesar de su nombre, no dice el tipo de valor.
Oriol
2

Aquí hay un ejemplo donde undefinedtiene más sentido quenull :

Utilizo una función contenedora para JSON.parseque convierta su excepción en undefined:

// parses s as JSON if possible and returns undefined otherwise
// return undefined iff s is not a string or not parseable as JSON; undefined is not a valid JSON value https://stackoverflow.com/a/14946821/524504
function JSON_parse_or_undefined(s) {
    if ("string" !== typeof s) return undefined

    try {
        const p = JSON.parse(s)
        return p
    } catch (x){}

    return undefined
}

Tenga en cuenta que nulles válido en JSON mientras undefinedque no lo es.

masterxilo
fuente
Veo lo que estás haciendo allí, y no puedo decir que te equivoques, porque en cierto sentido creo que podrías hacer esto aquí y estaría bien. Tengo un patrón diferente que utilizo para hacer esta operación que me gusta más porque hago un paso de "validación" después. Siento que esto está mezclando la validación con la devolución del valor. Aquí es lo que hago: let getStringOrJSON = value => { try { value = JSON.parse(value); } catch(e) { return value; } return value; };. Ahora, estoy seguro de que las dos devoluciones podrían manejarse de manera diferente y es posible que no ganen la competencia de golf JS. Funciona.
Jeremy Iglehart
1

La primera respuesta es correcta. Tienen un significado teóricamente diferente. Sin embargo, no siempre está claro cuál elegir.

Tiendo a usar null en mi desarrollo, aunque creo que eso es algo completamente subjetivo.

Lo uso principalmente porque:

  1. La variable indefinida podría sobrescribirse en navegadores antiguos, por lo que devolverla es un poco más complicado. Este mismo problema te obliga a usar typeof var === 'undefined'cuando obtienes resultados de funciones. enlace

  2. Otros lenguajes tienden a usar null ampliamente, muchos de ellos ni siquiera tienen undefined (php por ejemplo). Eso me da cierta coherencia al cambiar rápidamente entre idiomas.

Maciej Paprocki
fuente
1

Creo que es muy discutible qué usar. Prefiero un código que sea semánticamente lo más preciso posible, así que creo que undefinedes apropiado en este caso.

Creo que las nullasignaciones significan "una variable definida en nada". Esto es en contraposición a undefinedsignificar "esta cosa no existe en absoluto"

Como se señaló en una respuesta anterior, regresar undefinedtiene problemas, y depende completamente de usted si eso le molesta. No me molestaría.

Ryan Laboucane
fuente
2
Pero document.getElementById('iDoNotExist')regresa null, a pesar de que el significado se acerca más a "esta cosa no está allí". Si los métodos estándar lo hacen, ¿por qué no OP?
Oriol
@Oriol De hecho, me gusta más tu razonamiento. Por favor publique una respuesta a este efecto y la aceptaré. (Incluso podría agregar algunas ediciones si es necesario)
Jeremy Iglehart
Yah @Oriol, esta es la razón por la que disfruto los debates, incluso en los sitios de preguntas y respuestas. Es muy bueno tener contraejemplos. Y ha proporcionado uno bueno.
Ryan Laboucane
1

Yo diría que en este caso, nulldebería devolverse.

Si considera la pregunta desde un punto de vista teórico de la informática, entonces indefinido se usa para indicar no terminación / no computabilidad (es decir, el marcador de posición para un punto indefinido xde una función parcial f que a menudo se escribef(x) = ⊥ ).

getNextCardsin embargo, parece poder calcular la siguiente tarjeta (si existe) y también poder calcular si no hay una siguiente tarjeta. En otras palabras, la función es total ya que termina para cada entrada.

Dicho esto, se requiere una terminación de señalización de valor especial sin un resultado significativo (es decir, "no hay tarjeta que pueda devolver para esta entrada") y esto para mí nullno lo es undefined.


NOTAS:

Puede ver algo de soporte para este argumento en algunos otros lenguajes tipados, así como donde la terminación sin un resultado significativo se expresa usando un tipo de opción (a veces también denominado tipo anulable ). Un ejemplo de esto es Quizás en Haskell. .

Por otro lado, por supuesto, no sabemos qué undefinedse supone que significa realmente en JavaScript. Entonces, la analogía con indefinido es un poco tenue. Además, dado que siempre queremos trabajar con funciones totales, esto equivale a decir "nunca volver undefinedde una función". Lo que parece ser un poco estricto, ya que limitaría el uso de undefineda propiedades / variables que no se han establecido.

Al final, mi preferencia personal es no regresar nunca a undefineddonde puedo regresar nully también diría que esta es la mejor convención de codificación (porque entre otras cosas x !== nulles más corta que typeof x !== 'undefined').

FK82
fuente
-2

Mi opinión personal de acuerdo con mi experiencia es que no use undefined y null si no quiere bloquear su código. Al menos lo evitaría personalmente. Hay muchas funciones en Javascript que devuelven undefined y, bien, debemos usarlas. Pero cuando diseñe su código, no lo use. Es importante devolver siempre algo "false"al menos. Si tiene una matriz, por ejemplo, y la asigna. No es bueno volver [undefined, undefined.....]o simplemente undefined. Es mejor si mantiene el tipo de la matriz original. Ejemplo:

 const mapper:Map <string[],boolean[]>  
['i', 'dont', 'use', 'null or undefined'] -> [false, true, false, true, false]
or ['', dont, '', '', use] 
or al the stuff above and then filter(v => v)
that will keep all undefined and null out

Esa es la idea. Intento todo el tiempo evitarlo. Porque una nullo undefinedpuede bloquear fácilmente su código

rubendmatos1985
fuente