¿Por qué hay un valor "nulo" en JavaScript?

115

En JavaScript, hay dos valores que básicamente dicen 'No existo' undefinedy null.

Una propiedad a la que un programador no ha asignado nada será undefined, pero para que se convierta en una propiedad null, nulldebe asignársele explícitamente.

Una vez pensé que había una necesidad nullporque undefinedes un valor primitivo y nullun objeto. No lo es, incluso si typeof nullcederá 'object': en realidad, ambos son valores primitivos, lo que significa que ni undefinedni nullpueden devolverse desde una función de constructor, ya que ambos se convertirán en un objeto vacío (uno tiene que lanzar un error para proclamar falla en los constructores).

Ambos también se evalúan falseen contextos booleanos. La única diferencia real en la que puedo pensar es que uno evalúa y NaNel otro 0en contextos numéricos.

Entonces, ¿por qué hay ambos undefinedy nullsi esto solo confunde a los programadores que están verificando incorrectamente nullcuando intentan averiguar si se ha establecido una propiedad o no?

Lo que me gustaría saber es si alguien tiene un ejemplo razonable en el que sea necesario usar y nullque no se pueda expresar usando en su undefinedlugar.

Entonces, el consenso general parece ser que undefinedsignifica 'no existe tal propiedad' mientras que nullsignifica 'la propiedad existe, pero no tiene valor'.

Podría vivir con eso si las implementaciones de JavaScript realmente hicieran cumplir este comportamiento, pero undefinedes un valor primitivo perfectamente válido, por lo que puede asignarse fácilmente a propiedades existentes para romper este contrato. Por lo tanto, si desea asegurarse de que existe una propiedad, debe usar el inoperador o de hasOwnProperty()todos modos. Entonces, una vez más: ¿cuál es el uso práctico de valores separados para undefinedy null?

De hecho, lo uso undefinedcuando quiero desarmar los valores de las propiedades que ya no se usan pero que no quiero delete. ¿Debería usar nullen su lugar?

Christoph
fuente
3
Para responder a su última pregunta: No, no debería establecer propiedades en undefined.
Shog9
4
"indefinido" es solo una variable en el ámbito global con el valor primitivo "indefinido". Es posible definir otro valor para la variable: {undefined = "Hola"; alerta (sin definir);} Una forma más fiable a prueba de indefinido: {if (typeof mivar === "indefinido") alert ( "indefinido")}
algunos
1
Consulte la sección 4.3.9 - 12 en ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf para undefined / null, y 15.1.1.3 para la variable "undefined" en el ámbito global.
un
1
Debería eliminar un objeto o establecerlo en nulo si tiene más sentido, pero no en indefinido.
un
4
In JavaScript, there are two values which basically say 'I don't exist' - undefined and null.No, solo undefineddice eso.
Lightness Races in Orbit

Respuestas:

78

La pregunta no es realmente "¿por qué hay un valor nulo en JS"? Hay un valor nulo de algún tipo en la mayoría de los lenguajes y generalmente se considera muy útil.

La pregunta es, "¿por qué hay un valor indefinido en JS". Principales lugares donde se usa:

  1. cuando declara var x;pero no le asigna, se xmantiene indefinido;
  2. cuando su función obtiene menos argumentos de los que declara;
  3. cuando accede a una propiedad de objeto inexistente.

nullciertamente habría funcionado igual de bien para (1) y (2) *. (3) realmente debería lanzar una excepción de inmediato, y el hecho de que no lo haga, en lugar de devolver este extraño undefinedque fallará más adelante, es una gran fuente de dificultad de depuración.

*: también podría argumentar que (2) debería lanzar una excepción, pero entonces tendría que proporcionar un mecanismo mejor y más explícito para los argumentos predeterminados / variables.

Sin embargo, JavaScript no tenía originalmente excepciones, ni ninguna forma de preguntarle a un objeto si tenía un miembro con un nombre determinado; la única forma era (y a veces lo sigue siendo) acceder al miembro y ver lo que obtiene. Dado que nullya tenía un propósito y es posible que desee asignarle un miembro, se requería un valor fuera de banda diferente. Así que lo tenemos undefined, es problemático como usted señala, y es otra gran 'característica' de JavaScript de la que nunca podremos deshacernos.

De hecho, uso undefined cuando quiero desarmar los valores de las propiedades que ya no están en uso pero que no quiero eliminar. ¿Debería usar null en su lugar?

Si. Mantener undefinedcomo un valor especial para señalar cuando otros lenguajes podrían lanzar una excepción en su lugar.

nulles generalmente mejor, excepto en algunas interfaces DOM de IE donde configurar algo nullpuede generar un error. A menudo, en este caso, la configuración de la cadena vacía tiende a funcionar.

bobince
fuente
10
Los argumentos son expandibles. Puede colocar tantos como desee y una función podría iterar y hacer uso de todos ellos. A los objetos se les puede asignar una nueva propiedad en cualquier momento. Ambas son características poderosas, pero sospecho que tener excepciones lanzadas como preferiría sería una gran sobrecarga. En mi opinión, vale la pena el intercambio. Dedico mucho menos tiempo a verificar la existencia en JS que lo que normalmente hago en paradigmas de lenguaje más estrictos.
Erik Reppen
Es curioso cómo la respuesta aceptada a una pregunta comienza con "esta no es realmente la pregunta ..."
Phillip
@bobince, ¿las primeras versiones de JS no tenían el inoperador o hasOwnProperty? Porque son mucho más seguros que obj.hello !== undefinedcomprobar si existe una propiedad en un objeto.
Andy
No importa, respondí mi propia pregunta. Según MDN, ambos se introdujeron en ES3.
Andy
37

Se describe mejor aquí , pero en resumen:

undefined es la falta de un tipo y valor, y null es la falta de un valor.

Además, si está haciendo comparaciones simples '==', tiene razón, salen igual. Pero prueba ===, que compara el tipo y el valor, y notarás la diferencia.

Eddie Parker
fuente
1
Lo sé null !== undefined, mi pregunta era por qué se necesitaban dos cosas que expresaran el mismo concepto semántico; Además, su enlace menciona que 'nulo es un objeto'; eso está mal, es un primitivo ...
Christoph
2
No son el mismo concepto semántico. Para mí, al menos, hay una diferencia significativa entre una propiedad a la que se le asigna un valor nulo y una propiedad que no existe.
Daniel Schaffer
Pero eso es todo, no son el mismo concepto semántico. Null se coacciona cuando se usa == para implicar lo mismo, como una conveniencia para el programador.
Eddie Parker
1
@EricElliott: typeofmentiras - lea la especificación o intente regresar nullde un constructor
Christoph
5
@EricElliott: el valor de retorno de los constructores no tiene nada que ver con falsedad, sino con objetividad: si el valor de retorno es un objeto, devuélvelo; si es un primitivo como nullo 42, descarte el valor de retorno y devuelva el objeto recién creado en su lugar
Christoph
17

No creo que haya ninguna razón para tener ambos nully undefined, porque la única razón por la que muchas personas han sugerido (" undefinedsignifica que no existe tal variable / propiedad") no es válida, al menos en JavaScript. undefinedno puedo decirle si la variable / propiedad existe o no.

console.log(foo);               // "ReferenceError: foo is not defined"
                                // foo does not exist
var foo;
console.log(foo);               // "undefined", a different response
console.log(foo === undefined); // "true", but it does exist

var obj = {};
console.log(obj.hasOwnProperty("foo")); // "false", no such property
obj.foo = undefined;
console.log(obj.hasOwnProperty("foo")); // "true", it exists and has the value "undefined"
console.log(obj.foo === undefined);     // "true", but it does exist

obj.bar = "delete me";
obj.bar = undefined;
console.log(obj.hasOwnProperty("bar")); // "true", not actually deleted
delete obj.bar;
console.log(obj.hasOwnProperty("bar")); // "false", deleted

Como puede ver, la comprobación foo === undefinedno le indica si fooexiste y la configuración obj.bar = undefinedno se elimina realmente bar.

Puede ser la intención original del autor de JavaScript la que undefineddebería representar "inexistencia". Sin embargo, la implementación no resultó de esa manera.

Lei Zhao
fuente
1
Reemplace undefinedcon nullen sus ejemplos de código anteriores, y las respuestas son todas iguales. No estoy seguro de cómo esto responde a la pregunta. ¿Fue esto como un comentario sobre la respuesta de otra persona?
Eric Elliott
1
@EricElliott Mi respuesta a la pregunta es que no hay razón para tener ambos nully undefined, porque la única razón por la que muchas personas han sugerido no es válida.
Lei Zhao
Debes editar tu respuesta y decir eso. Podría haber votado a favor si hubieras dado esa respuesta. =)
Eric Elliott
@EricElliott Creo que tienes razón. He editado mi respuesta. ¡Gracias!
Lei Zhao
3
Este ejemplo realmente muestra que si no asignó una variable, regresa undefined. Pero si lo asignó undefined, en realidad no lo es undefined: se definió con él undefinedy hace referencia a él. La única diferencia entre undefinedy nulles su uso y propósito histórico. Ambos son atómicos.
Aleksej Komarov
6

Es completamente posible necesitar ambos. Por ejemplo, si consulta WMI, es totalmente posible que una clase devuelva propiedades que tengan un valor nulo. Están definidos, simplemente son nulos en ese momento.

EBGreen
fuente
6

Creo que su conclusión de que JavaScript define undefinedcomo "no existe tal propiedad" y nullcomo "la propiedad no tiene valor" es perfectamente correcta. Y en un lenguaje tan dinámico como JavaScript es una distinción muy importante. El uso del tipo de pato significa que debemos poder diferenciar entre una propiedad que no existe y que no tiene valor. Es nuestro medio principal de derivar información de tipo. en un lenguaje de tipo estático hay una distinción definida entre un campo que es nulo y un campo que no existe. En JavaScript esto no es diferente. Sin embargo, se comprueba en tiempo de ejecución y se puede modificar hasta ese momento.

Voy a tener que estar de acuerdo en que la implementación es extraña ya que muchas veces la distinción es borrosa. Sin embargo, creo que en JavaScript la distinción es importante. Y poder asignar undefinedes fundamental.

Recuerdo haber leído una publicación de blog hace un tiempo sobre un juego de rol en línea escrito en JavaScript. Usó ejemplos en los que los objetos se crearon como copias de instancias existentes en lugar de prototipos (clases, funciones, lo que sea) y luego se modificaron. Esto realmente me hizo entender lo poderoso que undefinedpodría ser al modificar objetos existentes, pero no recuerdo quién lo escribió.

Jack Ryan
fuente
¿Podrías compartir este juego de rol?
Michael
3

Semánticamente, significan cosas diferentes. El tipo nulo tiene exactamente un valor en su dominio, nulo y se le puede asignar a una propiedad este valor específico. Indefinido representa una clara falta de asignación de valor.

AnthonyWJones
fuente
1
pero puede usar undefinedbien para asignar propiedades, por lo que este contrato (solo se devuelve undfinedsi no hay tal propiedad) puede ser roto fácilmente por el programador ...
Christoph
2
Usted puede , pero definitivamente no debería. Undefined se usa como una forma de excepción muy básica / simplista en JavaScript: ¡no lo use como un valor y asígnelo a alguna propiedad! Eso es loco.
rfunduk
3

Como programador de Java, veo una gran diferencia entre indefinido y nulo. Codificación de JavaScript, no tanto, porque JavaScript no está fuertemente tipado, y las diferencias entre indefinido y nulo se ven borrosas por las conversiones automáticas que se realizan con frecuencia en tiempo de ejecución. Por cierto, aprovecho con frecuencia esas conversiones; hacen que mi código JS sea más compacto y legible.

Para responder a su pregunta, indefinido significa que nunca se estableció un valor. En términos prácticos, esto generalmente indica un error. Si yourObject.property no está definido, eso significa que no configuró la propiedad por alguna razón, o estoy buscando algo que no existe en absoluto. Este es un problema real cuando se trabaja en un proyecto con más de un codificador.

null significa que "sin valor" se estableció explícitamente. Hablando en términos prácticos, me está diciendo algo sobre la propiedad, tal vez que no se usa en este contexto o que aún no se ha determinado un valor.

En Java, los intentos de acceder a un campo que no está definido siempre darán como resultado una excepción. De hecho, se puede hacer que el compilador le advierta sobre esto en su código.

Steve11235
fuente
0

Prueba este ejemplo:

<html>
<head>
    <script type="text/javascript">
        function ShowObjProperties(obj) {
            var property, propCollection = "";

            for(property in obj) {
                propCollection += (property + ": " + obj[property] + "\n");
            }

            alert(propCollection);
        }

        var obj = {
            userid: 3,
            name: 'me!',
            speak: function() { alert('Hi! My name is ' + this.name + ' and my ID is ' + this.userid + '.'); }
        }

        //Shows all properties
        ShowObjProperties(obj);

        //The Speak function is no longer in the list!
        delete obj.speak;
        alert(typeof obj.speak);
        ShowObjProperties(obj);

        //The UserID is still listed, it just has no value!
        obj.userid = null;
        ShowObjProperties(obj);
    </script>
</head>
<body>

</body>
</html>

Creo que hay un uso muy real para 2 tipos diferentes aquí.

En peligro de extinción
fuente
Y en los prototipos, creo que es un miembro nulo o simplemente indefinido.
Kev
pero esto solo funciona mientras nadie intente romperlo; si lo configuro obj.userid = undefined, fallará; vea la última edición de mi pregunta
Christoph
0

Todo se reduce a la naturaleza dinámica de los javascripts.

Las cosas pueden no estar definidas para que se puedan agregar en un momento posterior. Podría decirse que esta es la razón por la que JavaScript es tan poderoso y extensible.

Rob Stevenson-Leggett
fuente
y esto es relevante para mi pregunta ¿de qué manera?
Christoph
2
Es relevante porque responde a tu pregunta. 'null' es una especie de 'singleton' que significa que 'no tiene valor'. 'undefined' te está diciendo que algo es ... impactante, lo sé ... no definido. Son cosas completamente diferentes.
rfunduk
0

es una característica importante del lenguaje si envuelve su programa en el paradigma de JavaScript.

// a key exists as a placeholder for something
if(obj[name] === null) 
// no key exists int eh hashtable that is in this object
if(obj[name] === undefined)

esto es muy útil si está tratando con un conjunto de datos que necesita un valor para representar "nada" para indicar alguna acción diferente de usar "nada" para indicar la acción predeterminada.

filter_func_pt = {
  date:function(d){ return Math.round(d.getTime()/1000);},
  user: null,
}

function transform(obj){
    var ret = {};
    for( var prop in obj){
       var f = filter_func_pt[prop];
       if(f)
          ret[prop] = f(obj);
       else if(filter_func_pt[prop] === null)
         continue;
       else
         ret[prop] == obj;
    }
  return ret;
}

var a = {
   date: new Date(),
   user: 'sam'
   votes: [23, 41, 55] 
};

var b = transform(a);

/* b = {
 *    date: 1298582417
 *    votes: [23, 41, 55]
 * }
 */

en el código anterior la palabra clave nula y el servidor indefinido son muy claros y con diferentes propósitos. la búsqueda que no se encuentra en el objeto filter_func_pt que devuelve undefined significa agregar la propiedad al objeto devuelto como está, mientras que un valor nulo indica que el valor debe retenerse, y no agregarse, y la presencia de cualquier valor verdadero en este case representa una función utilizada para transformar el valor antes de agregarlo al objeto ret .

Cuervo de fuego
fuente
Este ejemplo es artificial y un poco absurdo. Null no aclara su intención en absoluto; más bien, la enmascara. Podrías haber usado una cadena más explícita para aclarar el significado. Como, 'retener' o 'eliminar' y luego también podría ser más explícito sobre el tipo de función y verificar la presencia de una función.
Eric Elliott
0

nulo es hermoso

al igual que todos los demás tipos de Live Script.

cite: En JavaScript, hay dos valores que básicamente dicen 'No existo': indefinido y nulo.

¿Por qué querrías decir cosas incorrectas?

"nulo" es "Objeto vacío" al igual que "0" es un "Número vacío" . 0, no es nada; sin embargo, existe como un tipo de cosa numérica. null, por supuesto, también está vacío, pero "es" y es una cosa bien definida de un tipo de objeto .

Es común hablar de estas cosas como de "tipos", cuando no lo son. De hecho son "categorías". Pero eso ya terminó.

Así que nos atenemos a él para decir que "nulo" es un tipo de objeto sin un tipo. Y "nulo" dice "¡Existo mucho [!], Pero no tengo contenido de mi tipo".

Mientras que undefined carece tanto del tipo como del tipo, donde indefinido también es su definición de tipo. Un tipo indefinido de un tipo se convierte en su tipología distintiva. Una especie de pregunta [¿existe "nada" y cómo se define "nada"?].

cite: undefined ni null se pueden devolver desde una función constructora, ya que ambos se convertirán en un objeto vacío

Has conseguido decir una vez más algo incorrecto. Por supuesto que no, lo "indefinido" no es un Objeto, es un Token simple que los humanos entendemos; pero contrario a ese nulo es - y te dice que: su Tipo es correcto, pero el Tipo que estás buscando no está contenido en él, o al menos - no en este momento. Ven a visitarnos más tarde cuando le pongamos \ asignar algún objeto \.

cite: La única diferencia real en la que puedo pensar es que uno evalúa a NaN, el otro a 0 en contextos numéricos.

Eso hace todo el punto de su distinción central, como se mencionó: undefined es un token simple y dado que está hecho del mismo material 'genético' que sus parientes lejanos: strings, la operación [+ undefined] lo convertirá en NaN, de manera similar, null, por supuesto, se transformará en un número correcto de 0 \ Number, y a diferencia de undefined, se transformará en una cadena (! Que no está vacía!) Y es exactamente por eso que produce NaN en su lugar. Donde: + indefinido >> + "indefinido" >> NaN. Dado que el contexto numérico espera un valor explícito.

Si bien el contexto booleano espera una referencia, no encuentra nada para convertir y produce 'falso'.

Cortemos ahora ...

cite: Entonces, una vez más: ¿cuál es el uso práctico de valores separados para indefinido y nulo?

Intentaré darles solo dos ejemplos empíricos y espero que sean suficientes.

oElement.onclick >> null

// significa -la propiedad existe; su valor esperado es de Type: Object , y ese oElement admite el evento "onclick".

oElement.innerText >> ""

// significa - la propiedad existe; su valor esperado es de Type: String , lo que significa que oElement admite la propiedad "innerText".

en ambos casos -si recibe "indefinido" significa que la propiedad no existe; no es compatible o tiene una implementación incorrecta (de un proveedor).

Mantente helado y diviértete.

Bill el lagarto
fuente
No destroces tus publicaciones, Eneas. Bórrelos (usando el botón Eliminar justo encima de este comentario) si desea eliminar su contribución.
Michael Petrotta
no hay un botón de eliminar, pero en caso de que lo vea, ¡haga clic en él!
0

después de leer una discusión increíble sobre undefined vs null, una pequeña búsqueda en Google me llevó a Mozilla Documentations https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null se menciona - null es a menudo recuperado en un lugar donde se puede esperar un objeto pero ningún objeto es relevante.

No es similar al patrón de objeto nulo https://en.wikipedia.org/wiki/Null_object_pattern

Así que supongo que tiene sentido tener un tipo de datos nulo.

La documentación también se menciona como tipo de nulo // "objeto" (no "nulo" por motivos heredados)

No estoy seguro de cuáles son las razones heredadas

Vishal Bhandare
fuente