Operador de Fusión Nula en JavaScript (??)
Aprende el operador de fusión nula (??) de JavaScript, cómo difiere de ||, reglas de precedencia y los operadores de asignación lógica ??=, &&= y ||=.
El operador de fusión nula (??) es una forma concisa y expresiva de proporcionar un valor predeterminado en JavaScript. Devuelve su operando derecho solo cuando el operando izquierdo es nulo — es decir, null o undefined — y en caso contrario devuelve el valor izquierdo sin modificarlo. Introducido en ES2020, resuelve un problema histórico con el uso del operador || para valores predeterminados, y funciona en conjunto con el encadenamiento opcional y los operadores lógicos que ya conoces.
Qué Significa "Nulo"
Un valor se considera nulo cuando es exactamente null o undefined. Cualquier otro valor — incluyendo los falsos como 0, '', false y NaN — es tratado como un valor real e intencional por ??.
null ?? 'default' // 'default'
undefined ?? 'default' // 'default'
0 ?? 'default' // 0
'' ?? 'default' // ''
false ?? 'default' // false
NaN ?? 'default' // NaNLa regla es simple: si el lado izquierdo es null o undefined, obtienes el lado derecho; de lo contrario obtienes el lado izquierdo.
Cómo Difiere ?? de ||
Esta es la razón más importante por la que existe ??. El operador OR lógico (||) devuelve el lado derecho siempre que el lado izquierdo sea cualquier valor falso — 0, '', false, NaN, null y undefined todos cuentan. Ese comportamiento está bien hasta que 0 o una cadena vacía es un valor legítimo, momento en el que || produce silenciosamente el resultado incorrecto.
Considera un contador cuyo valor válido puede ser 0:
let count = 0;
let withOr = count || 100; // 100 — ¡incorrecto! 0 fue reemplazado
let withNullish = count ?? 100; // 0 — correcto, 0 fue preservadoDado que 0 es falso, || lo trata igual que "sin valor" y recurre a 100. El operador ?? reconoce que 0 no es nulo y lo conserva. La misma trampa se aplica a las cadenas vacías:
Usa ?? en lugar de || siempre que 0, '' o false sean entradas válidas. Usar || para valores predeterminados en esos casos es una de las fuentes más comunes de errores sutiles en JavaScript — por ejemplo, una cantidad de 0 convirtiéndose en 1, o un campo de búsqueda vacío tomando un texto de marcador de posición.
Precedencia y Paréntesis
El operador ?? tiene baja precedencia — aproximadamente el mismo nivel que || y menor que los operadores aritméticos y de comparación. En la práctica, esto significa que el valor de reserva se resuelve antes de que el valor se use en una expresión más grande, pero aun así deberías agrupar con paréntesis para mantener la intención clara.
let height = null;
let width;
// Each ?? is evaluated, then the products are multiplied
let area = (height ?? 100) * (width ?? 50);
console.log(area); // 100 * 50 = 5000Sin los paréntesis, la multiplicación vincularía más estrechamente de lo que podrías esperar, por lo que envolver cada valor predeterminado en ( ... ) mantiene la operación sin ambigüedades y legible.
Combinar ?? Con && o || Está Prohibido
JavaScript deliberadamente no permite mezclar ?? con && o || en la misma expresión sin paréntesis. Hacerlo es un SyntaxError, porque la precedencia entre ellos sería ambigua y fácil de malinterpretar.
// SyntaxError: Unexpected token '||'
let result = a ?? b || c;
// Fix it by grouping explicitly:
let safe = (a ?? b) || c; // valid
let other = a ?? (b || c); // also valid, different meaningLas dos formas válidas significan cosas diferentes, razón por la cual el lenguaje te obliga a elegir. Añade los paréntesis y establece con precisión lo que pretendes.
La restricción solo se aplica cuando ?? aparece directamente junto a && o ||. Puedes usarlos libremente en expresiones separadas, y los paréntesis siempre resuelven la ambigüedad.
Operadores de Asignación Lógica
ES2021 añadió tres operadores de asignación lógica que combinan una asignación con una verificación lógica. Asignan a la variable del lado izquierdo solo cuando se cumple una condición, lo que los hace perfectos para establecer valores predeterminados y actualizaciones condicionales.
Asignación Nula (??=)
x ??= y asigna y a x solo si x es actualmente null o undefined. Es la forma de asignación de ?? y la más común de las tres para establecer valores predeterminados en un object.
let settings = { theme: 'dark' };
settings.theme ??= 'light'; // already set → stays 'dark'
settings.fontSize ??= 16; // missing → becomes 16
console.log(settings); // { theme: 'dark', fontSize: 16 }Asignación OR Lógico (||=)
x ||= y asigna y a x cuando x es falso (0, '', false, null, undefined, NaN). Al igual que ||, puede sobrescribir valores falsos válidos, así que úsalo solo cuando cualquier valor falso realmente signifique "reemplázame".
Asignación AND Lógico (&&=)
x &&= y asigna y a x solo cuando x es verdadero. Es útil para actualizar un valor que ya existe sin crearlo.
let config = { token: 'abc123' };
config.token &&= config.token.trim(); // truthy → trimmed and reassigned
config.missing &&= 'never set'; // undefined → left untouched
console.log(config); // { token: 'abc123' }Cada operador también cortocircuita: solo evalúa y asigna el lado derecho cuando la condición lo requiere, por lo que los efectos secundarios del lado derecho se omiten cuando la asignación no ocurre.
Usos en el Mundo Real
El operador ?? brilla en cualquier lugar donde un valor pueda legítimamente estar ausente mientras que 0 o '' deben ser respetados. Los escenarios típicos incluyen leer configuraciones, establecer valores predeterminados para parámetros de función opcionales y extraer campos de respuestas API.
// 1. Default options merged with user input
function createButton(options) {
let label = options.label ?? 'Submit';
let count = options.count ?? 0; // 0 stays 0, never becomes a default
return { label, count };
}
// 2. Reading a possibly-missing API field
let response = { data: { user: { nickname: null } } };
let name = response.data.user.nickname ?? 'Guest';
console.log(name); // 'Guest'Funciona especialmente bien con el encadenamiento opcional (?.). El encadenamiento opcional devuelve undefined de forma segura cuando parte de una ruta está ausente, y ?? entonces proporciona el valor de reserva en una sola línea limpia:
let city = user?.address?.city ?? 'Unknown';Esto se lee como: "Usa la ciudad del usuario si toda la cadena existe, de lo contrario usa 'Unknown'." Para decidir cuál de dos rutas tomar basándose en una condición, el operador condicional (ternario) sigue siendo la mejor herramienta — ?? es específicamente para proporcionar valores predeterminados para valores nulos.
Soporte de navegadores: ?? es parte de ES2020 y los operadores de asignación lógica (??=, ||=, &&=) llegaron en ES2021. Todos los navegadores modernos y Node.js 14+ los admiten. Si debes apuntar a entornos muy antiguos, un transpilador como Babel puede compilarlos.
Resumen
??devuelve el operando derecho solo cuando el izquierdo esnulloundefined; de lo contrario devuelve el izquierdo.- Prefiere
??sobre||para valores predeterminados cuando0,''ofalseson valores válidos. ??tiene baja precedencia — agrupa con paréntesis, y nunca lo coloques directamente junto a&&o||sin paréntesis (eso es unSyntaxError).??=,||=y&&=asignan condicionalmente: en nulo, en falso y en verdadero respectivamente.- Combina
??con el encadenamiento opcional (?.) para leer datos posiblemente ausentes y establecer un valor predeterminado en una sola expresión.