Javascript: null vs undefined

Todos los lenguajes de programación necesitan manejar diferentes tipos de datos. Dentro de esos tipos de datos existen: texto, números, booleanos, etc. A veces más, a veces menos dependiendo de cada lenguaje.

Pero adicionalmente a esos tipos de datos se necesita la capacidad de representar la falta de valor, de definición. En Javascript esto se maneja con los tipos de dato null y undefined.

¿Pero por qué 2 tipos de datos para este propósito?

Otros lenguajes solo utilizan 1 concepto para representar la ausencia de valor:

  • En Python se utiliza None.
  • En PHP existe NULL.
  • En Java se utiliza null (aunque no lo consideran un tipo de dato).

Sin embargo en Javascript hay 2. ¿Por qué? ¿Cuál es la diferencia entre null y undefined?

Probablemente te haz topado con una imagen similar a la siguiente.

4 imagenes. Rollo de papel representa a un valor mayor a 0. Rollo de papel vacío representa el valor 0. La ausencia de rollo de papel  pero aun con el contenedor representa null. La ausencia de todo representa undefined.

Esta imagen es una buena representación de la diferencia, aunque igual necesita un poco de explicación.

  • null representa la ausencia de un valor de manera intencional.
  • undefined representa que no se ha asignado un valor.

Sin embargo esto no te dice mucho de como utilizar ambos valores en código. Ambos representan que no hay valor, pero la incógnita sigue: ¿Cuando usamos uno y cuando usamos otro?

Primero que nada tienes que tener claras las diferencias de comportamiento entre ambas.


Las diferencias

Tipos de dato

null y undefined son tipos de datos primitivos en Javascript, así como Number, Boolean o String. Esto da pie a pensar que entonces el tipo de dato de null y undefined pues es igual a ellos mismos.

Esto lo puedes corroborar con typeof.

typeof(null)       // object
typeof(undefined)  // undefined

undefined si cumple con las expectativas, pero null no. ¿Por qué pasa esto?

La respuesta probablemente no te satisfaga, pero esto es considerado como un error.

Así es. El lenguaje de programación de Javascript tiene errores. ¿Por qué no se corrige?

JS tiene el propósito de ser retrocompatible. Esto es por que hay muchos sitios en la web que estan hechos con versiones previas del lenguaje. Si se hicieran cambios que anularan comportamientos anteriores se podrían afectar el funcionamiento y romper varios sitios.

Esto significa que nos toca vivir con los errores del pasado.

Coerción Implícita

La coerción implícita se refiere al proceso de conversión entre diferentes tipos de datos dependiendo del contexto.

null

Tipo de ConversiónValor representado
Booleanfalse
Number0

undefined

Tipo de ConversiónValor representado
Booleanfalse
NumberNaN

*Coerción Implícita es un tema más grande que esto. Puedes aprender más acerca de este proceso aquí.

Ejemplo

Con estas diferencias en mente, veamos como difiere null y undefined en el escenario más común:

null

async function fiilFormOptions (newEnrollment) {
    let enrolledDate = null
    let studentProfile = null
    let lastSelectedCourse = null

    if (!newEnrollment) {
        enrolledDate = await fetch('someUrl/1')
        studentProfile = await fetch('someUrl/2')
        lastSelectedCourse = await fetch('someUrl/3')

        if (enrolledDate === null) {
            throw Error('Error retrieving enrolledDate')
        }
    }

}

undefined

async function fiilFormOptions (newEnrollment) {
    let enrolledDate = undefined
    let studentProfile = undefined
    let lastSelectedCourse = undefined

    if (!newEnrollment) {
        enrolledDate = await fetch('someUrl/1')
        studentProfile = await fetch('someUrl/2')
        lastSelectedCourse = await fetch('someUrl/3')

        if (enrolledDate === undefined) {
            throw Error('Error retrieving enrolledDate')
        }
    }

}

Como puedes ver es exactamente el mismo código y no cambia nada en la lógica o en el funcionamiento. Así que si se usan de la misma manera…entonces… ¿podríamos usarlos indiferentemente? ¿como si fueran lo mismo? Eso tampoco es del todo cierto tristemente. Recuerda lo que viste en la sección de Coerción Implícita.

null === undefined;      // false

Bueno, entonces ¿de qué sirve usar uno u otro?

Hay algo en lo que te puede ayudar , pero es más debido a una buena práctica que por que sea alguna funcionalidad que te ofrece Javascript.

La utillidad de null y undefined

Cuando declaras una variable, Javascript siempre la inicializa con el valor de undefined.

let value;      // undefined

Este es el comportamiento default de Javascript y no hay ningun escenario en el que se haga lo mismo con null.

De hecho puedes recordar la definición de null, al inicio de este post:

null representa la ausencia de un valor de manera intencional.

Por lo tanto te invitó a que adoptes la siguiente buena práctica:

Cuando necesites asignar explícitamente la ausencia de valor, hazlo con null. Tu como desarrollador jamás asignes undefined.

¿En qué te ayuda esto?

Si sigues esta regla, en el momento en el que te encuentres con un undefined sabrás que hay un error en la lógica de tu código, ya que dicha variable jamás tuvo un valor asignado por ti.

En cambio cuando te encuentres un null sabrás que dicha variable no tiene valor por una decisión consciente que hiciste como desarrollador.

Obviamente al ser solo una buena práctica y no una característica del lenguaje inevtiablemente te encontrarás con proyectos que no siguen esta regla.

Sin embargo cuando tengas la oportunidad de implementarlo en un proyecto desde el inicio (y mejor aún si puedes establecer la regla en un linter y en una guía de estilos de código) hazlo. De verdad te salvará de mucho tiempo de debuggeo.

Y al final que mejor que utilizar tu tiempo para los bugs realmente importantes.