¿Qué razón hay para usar nulo en lugar de indefinido en JavaScript?

103

He estado escribiendo JavaScript durante bastante tiempo y nunca he tenido una razón para usarlo null. Parece que undefinedsiempre es preferible y tiene el mismo propósito programáticamente. ¿Cuáles son algunas razones prácticas para usar en nulllugar de undefined?

Jimmy Cuadra
fuente
Este es un posible duplicado de stackoverflow.com/questions/461966/…
lawnsea
Bueno, hay métodos como document.getElementById()ese que pueden regresar nullpero no undefined, así que en esos casos, ¿por qué probarías el retorno undefined? (Claro, funcionaría si usa en ==lugar de ===, pero aún así, ¿por qué probaría deliberadamente lo incorrecto?)
nnnnnn
Puede ser útil tener tipos predecibles y esto puede guiar el pensamiento para usar uno u otro. Cuando un objeto siempre es devuelto, necesario o deseado por diseño, use null para resultados falsos (p document.getElementById('does-not-exist'). Ej .). Las variables var a;y los valores de retorno de funciones están predeterminados como indefinidos. En el pasado, null estaba en el alcance global, por lo que su uso ralentizó la ejecución y me llevó a preferir otros tipos falsos (false, '', 0) a las referencias gratuitas. Personalmente, evito el nulo a menos que haya una razón convincente de lo contrario porque lo percibo como más simple, lo que generalmente es mejor.
Jimmont

Respuestas:

59

Nulo e indefinido son esencialmente dos valores diferentes que significan lo mismo. La única diferencia está en las convenciones de cómo los usa en su sistema. Como algunos han mencionado, algunas personas usan nulo para significar "sin objeto" donde a veces puede obtener un objeto mientras que indefinido significa que no se esperaba ningún objeto (o que hubo un error). Mi problema con eso es que es completamente arbitrario y totalmente innecesario.

Dicho esto, hay una diferencia importante: las variables que no se inicializan (incluidos los parámetros de función donde no se pasó ningún argumento, entre otras cosas) siempre están indefinidas.

Es por eso que en mi código nunca uso nulo a menos que algo que no controlo devuelva nulo (coincidencia de expresiones regulares, por ejemplo). La belleza de esto es que simplifica mucho las cosas. Nunca tengo que comprobar si x === indefinido || x === nulo. Y si tiene la costumbre de usar == o simplemente cosas como if (x) .... Para. !xse evaluará como verdadero para una cadena vacía, 0, nulo, NaN, es decir, cosas que probablemente no desee. Si desea escribir javascript que no sea terrible, siempre use triple igual === y nunca use nulo (use undefined en su lugar). Te facilitará la vida.

BT
fuente
137
No estoy de acuerdo con esto. Null se usa para definir algo vacío programáticamente. Indefinido significa que la referencia no existe. Un valor nulo tiene una referencia definida a "nada". Si está llamando a una propiedad que no existe de un objeto, obtendrá indefinido. Si haría que esa propiedad se vacíe intencionalmente, entonces debe ser nula para que sepa que es a propósito. Muchas bibliotecas de JavaScript funcionan de esta manera.
com2ghz
6
@ com2ghz Lo que usted describe es una de las muchas filosofías. Muchas bibliotecas js funcionan de esa manera. Muchos tampoco funcionan de esa manera. En javascript, puede almacenar tan fácilmente un valor indefinido explícito en un objeto o matriz como con null. Los significados de ambos dependen total y completamente del contexto. Es decir, significan lo que tú quieres que signifiquen.
BT
3
Por eso JS es un lenguaje horrible. Como dices, muchas bibliotecas tienen sus propias filosofías, pero incluyes muchas bibliotecas para 1 proyecto. Entonces te encuentras con muchas convenciones de esas bibliotecas. ¿Cuántas veces necesita realizar diferentes comprobaciones falsas? No sería la última vez que concatena un objeto nulo en una cadena y obtiene un "nulo" como cadena. O pasar un 0 como valor numérico y preguntarse por qué la instrucción IF maneja t como falso.
com2ghz
2
@ com2ghz ¿Entonces JS es un lenguaje horrible porque tiene tanto nulo como indefinido? Puedo contar docenas de malas decisiones lingüísticas en todos los idiomas principales, js no es una excepción allí. Literalmente, nunca necesito o quiero usar verificaciones falsas en mi código y siempre uso ===o !==. JS es un lenguaje increíblemente expresivo si sabes cómo usarlo.
BT
6
Correcto. Me acabo de enterar de que la dicotomía null/ undefinedera necesaria porque la versión inicial de JS no tenía hasOwnPropertyo el inoperador. Ahora que lo hace, realmente no entiendo por qué uno de ellos no fue abolido en ES6 o cualquier propuesta de ES7 que haya visto.
Andy
86

Realmente no tengo una respuesta, pero según Nicholas C. Zakas , página 30 de su libro " JavaScript profesional para desarrolladores web " :

Cuando se define una variable que luego debe contener un objeto, es recomendable inicializar la variable en nullen lugar de cualquier otra cosa. De esa manera, puede verificar explícitamente el valor nullpara determinar si la variable se ha llenado con una referencia de objeto en un momento posterior.

bbg
fuente
8
+1 sí, estoy de acuerdo y siempre trato de recordar inicializar vars en nulo. Entonces estoy (bastante) seguro de que eso undefinedsignifica que ocurrió un desastre. Sólo en mi humilde opinión.
Pete Wilson
9
@Pete - pero no te dice nada sobre el "desastre", entonces, ¿cuál es el punto? Y solo puede hacer esa suposición si sabe que la función sigue la convención.
RobG
7
Por otro lado, también puede inicializar la variable con var myVar;y verificar explícitamente el valor undefinedpara determinar si se ha llenado con una referencia de objeto en un momento posterior. Mi punto es que esto es totalmente académico: puede hacerlo de cualquier manera, y cualquiera que aconseje de una manera sobre la otra simplemente está impulsando su propia convención.
jueves
1
El único problema que tengo (desde que empecé con JavaScript hace 15 años) es que con demasiada frecuencia tienes que probar undefinedy null. Esto sigue siendo realmente molesto. Evito asignar una variable a nullsolo para reducir el número de nullpruebas adicionales .
G Man
4
@GMan: este es el único lugar donde la ==comparación (a diferencia de ===) tiene sentido: v == null(o v == undefined) buscará nulo o indefinido.
Rick Love
14

Al final del día, debido a que ambos nully undefinedcoaccionan al mismo valor ( Boolean(undefined) === false && Boolean(null) === false), técnicamente puede usar cualquiera para hacer el trabajo. Sin embargo, hay una forma correcta, en mi opinión.

  1. Deje el uso de undefinedal compilador de JavaScript.

    undefinedse utiliza para describir variables que no apuntan a una referencia. Es algo que el compilador JS se ocupará por ti. En el momento de la compilación, el motor JS establecerá el valor de todas las variables elevadas en undefined. A medida que el motor recorre el código y los valores están disponibles, el motor asignará los valores respectivos a las variables respectivas. Para aquellas variables para las que no encontró valores, las variables continuarían manteniendo una referencia a la primitiva undefined.

  2. Utilice nulo solo si desea indicar explícitamente que el valor de una variable "no tiene valor".

    Como indica @ com2gz: nullse usa para definir algo vacío programáticamente. undefinedquiere decir que la referencia no existe. Un nullvalor tiene una referencia definida a "nada". Si está llamando a una propiedad no existente de un objeto, obtendrá undefined. Si quisiera vaciar esa propiedad intencionalmente, entonces debe ser nullpara que sepas que es a propósito.

TLDR; No uses el undefinedprimitivo. Es un valor que el compilador JS establecerá automáticamente cuando declare variables sin asignación o si intenta acceder a propiedades de objetos para los que no hay referencia. Por otro lado, use nullsi y solo si desea intencionalmente que una variable no tenga "valor".

Nunca establecí nada explícitamente como indefinido (y no me he encontrado con esto en las muchas bases de código con las que he interactuado). Además, rara vez utilizo null. Las únicas veces que uso nulles cuando quiero denotar el valor de un argumento a una función como si no tuviera valor, es decir:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Govind Rai
fuente
Esta debería haber sido la respuesta seleccionada
alaboudi
13

indefinido es donde no existe noción de la cosa; no tiene ningún tipo y nunca antes se ha hecho referencia a él en ese ámbito; nulo es donde se sabe que existe la cosa, pero no tiene valor.

Yaplex
fuente
4
¿Cómo saber si se intentó asignar un valor, pero falló y se asignó indefinido ?
RobG
11

Cada uno tiene su propia forma de codificar y su propia semántica interna, pero a lo largo de los años he descubierto que este es el consejo más intuitivo que le doy a las personas que hacen esta pregunta: en caso de duda, haga lo que hace JavaScript .

Digamos que está trabajando con propiedades de objeto como opciones para un complemento jQuery ... pregúntese qué valor le da JavaScript a una propiedad que aún no se ha definido; la respuesta es undefined. Entonces, en este contexto, inicializaría este tipo de cosas con 'indefinido' para que sean consistentes con JavaScript (para las variables, puede hacerlo en var myVar;lugar de var myVar = undefined;).

Ahora digamos que está manipulando DOM ... ¿qué valor asigna JavaScript a los elementos inexistentes? La respuesta es null. Este es el valor con el que inicializaría si está creando una variable de marcador de posición que luego contendrá una referencia a un elemento, fragmento de documento o similar que se relacione con el DOM.

Si está trabajando con JSON, entonces debe hacerse un caso especial: para valores de propiedad indefinidos, debe establecerlos en ""o nullporque un valor de undefinedno se considera el formato JSON adecuado.

Dicho esto, como se ha expresado en un póster anterior, si descubre que está inicializando cosas con nullo undefinedmás de una vez en una luna azul, tal vez debería reconsiderar cómo va a codificar su aplicación.

thdoan
fuente
Si bien esta es una buena postura, me gustaría agregar esta respuesta: stackoverflow.com/a/37980662/883303
Frederik Krautwald
@FrederikKrautwald gracias por el enlace, esa es una delineación muy clara.
jueves
10

Puede adoptar la convención sugerida aquí, pero realmente no hay una buena razón para hacerlo. No se usa con la suficiente coherencia para ser significativo.

Para que la convención sea útil, primero debe saber que la función llamada sigue la convención. Luego, debe probar explícitamente el valor devuelto y decidir qué hacer. Si no está definido , puede suponer que ocurrió algún tipo de error que la función llamada conocía . Pero si ocurrió un error y la función lo sabía, y es útil enviarlo a un entorno más amplio, ¿por qué no usar un objeto de error? es decir, arrojar un error?

Entonces, al final del día, la convención es prácticamente inútil en cualquier otra cosa que no sean programas muy pequeños en entornos simples.

RobG
fuente
3

Una propiedad útil en null que undefined no califica:

> null + 3
3
> undefined + 3
NaN

Lo uso nullcuando quiero 'apagar' un valor numérico o inicializar alguno. Mi último uso fue manipular la transformación css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

No estoy seguro de si debería usar esta propiedad pensando ...

Faccion
fuente
2

Los nodos y elementos DOM no están indefinidos, pero pueden ser nulos.

  • El nextSibling del último hijo de un elemento es nulo.

  • El hermano anterior del primer hijo es nulo.

  • Una referencia document.getElementById es nula si el elemento no existe en el documento.

Pero en ninguno de estos casos el valor está indefinido ; simplemente no hay ningún nodo allí.

Kennebec
fuente
Gracias por la explicación. Para mí, esto no podría ser más contrario a la intuición.
tomekwi
Realmente depende de lo que intente comprobar. Por ejemplo, si desea ver si existe una variable global llamada 'myVar', entonces window.myVardevolvería 'undefined si no existe. Hay toneladas de cosas que devuelven 'indefinido' en JavaScript, solo que hay toneladas de cosas que devuelven 'nulo', todo depende del contexto.
jueves
2

Algunos han dicho que está bien inicializar objetos en null. Solo quería señalar que los argumentos por defecto de desestructuración no funcionan null. Por ejemplo:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Esto requiere realizar nullcomprobaciones antes de llamar a la función, lo que puede suceder con frecuencia.

Matt Way
fuente
1

Estoy trabajando en esta pregunta exacta en este momento y estoy mirando la siguiente filosofía:

  1. Cualquier función que esté destinada a devolver un resultado debe devolver un valor nulo si no encuentra un resultado.
  2. Cualquier función que NO esté destinada a devolver un resultado devuelve implícitamente undefined.

Para mí, esta pregunta es importante porque cualquiera que llame a una función que devuelva un resultado no debería tener dudas sobre si probar indefinido o nulo.

Esta respuesta no intenta abordar:

  1. Valores de propiedad de nulo vs indefinido
  2. Las variables dentro de sus funciones son nulas frente a indefinidas

En mi opinión, las variables son su propio negocio y no una parte de su API, y las propiedades en cualquier sistema OO están definidas y, por lo tanto, deben definirse con un valor diferente de lo que serían si no se definieran (nulo para definido, indefinido es lo que obtener al acceder a algo que no está en su objeto).

Miguel
fuente
1

Aquí hay una razón: var undefined = 1 es javascript legal, pero var null = 1es un error de sintaxis. La diferencia es que nulles una palabra clave de idioma, mientras queundefined que, por alguna razón, no lo es.

Si su código se basa en comparaciones undefinedcomo si fuera una palabra clave ( if (foo == undefined)un error muy fácil de cometer), eso solo funciona porque nadie ha definido una variable con ese nombre. Todo ese código es vulnerable a que alguien defina accidental o maliciosamente una variable global con ese nombre. Por supuesto, todos sabemos que definir accidentalmente una variable global es totalmente imposible en javascript ...

Joel Mueller
fuente
1
Usar en void 0lugar de indefinido.
Frederik Krautwald
1

Solo quiero agregar que con el uso de ciertas bibliotecas de JavaScript, nulo e indefinido pueden tener consecuencias no deseadas.

Por ejemplo, la getfunción de lodash , que acepta un valor predeterminado como tercer argumento:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Otro ejemplo: si usa defaultProps en React, si se pasa una propiedad null, los accesorios predeterminados no se usan porque null se interpreta como un valor definido . p.ej

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
Lilbitofchee
fuente
0

No estoy de acuerdo en que el uso nulo o indefinido sea innecesario. indefinido es algo que mantiene vivo todo el proceso de encadenamiento de prototipos. Por lo tanto, el compilador solo con nulo no puede verificar si esta propiedad es igual a nula o si no está definida en el prototipo de punto final. En otros lenguajes de tipo dinámico (fe Python) arroja una excepción si desea acceder a una propiedad no definida, pero para los lenguajes basados ​​en prototipos, el compilador también debe verificar los prototipos principales y este es el lugar cuando los indefinidos más lo necesitan.

El significado completo de usar nulo es simplemente vincular la variable o propiedad con el objeto que es singleton y tiene significado de vacío, y también el uso nulo tiene fines de rendimiento. Este 2 código tiene un tiempo de ejecución diferente.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
VahagnNikoghosian
fuente
0

Variable desconocida: undefined.

Variable conocida todavía ningún valor: null.

  1. Recibe un objeto desde un servidor, server_object.
  2. Tu referencia server_object.errj. Te dice que lo es undefined. Eso significa que no sabe qué es eso.
  3. Ahora tu referencia server_object.err. Te dice que lo es null. Eso significa que está haciendo referencia a una variable correcta pero está vacía; por tanto, no hay error.

El problema es cuando declaras un nombre de variable sin un valor ( var hello) js declara que como undefined: esta variable no existe; mientras que los programadores principalmente quieren decir: "Todavía no le he dado un valor", la definición de null.

Entonces, el comportamiento predeterminado de un programador — declarar una variable sin un valor como nada — está en desacuerdo con js — declarar que no existe. Y además, !undefinedy !nullson ambos, la truemayoría de los programadores los tratan como equivalentes.

Por supuesto, puede asegurarse de que siempre lo hace, var hello = nullpero la mayoría no ensuciará su código como tal para garantizar la cordura de tipos en un lenguaje deliberadamente escrito, cuando ellos y el !operador tratan a ambos undefinedy nullcomo equivalentes.

newfivefour
fuente