Un Symbol es un tipo de dato primitivo en JavaScript que representa un identificador único y persistente.
A diferencia de otros tipos de datos primitivos como number, string o boolean, los símbolos son siempre únicos.
Esto significa que cada vez que creas un nuevo símbolo, obtienes un valor distinto que no se puede duplicar
- Unicidad: Cada
Symboles único e inmutable, lo que significa que dos símbolos nunca serán iguales. - No ennumerabilidad: Las propiedades de tipo
Symbolno son enumerables por defecto, lo que significa que no aparecerán en operaciones comofor...in.
El tipo de dato Symbol es uno de los tipos más avanzados y menos comprendidos, pero ofrece características útiles en ciertos contextos.
Creación de un Symbol
Para crear un Symbol, simplemente utilizamos la función constructora Symbol() sin la palabra clave new.
const mySymbol = Symbol();
En este ejemplo, id es un nuevo Symbol único e inmutable.
Descripción de un Symbol
Es posible proporcionar una descripción opcional al crear un Symbol. Esta descripción puede ser útil para identificar el propósito del Symbol.
const nombre = Symbol('Nombre del símbolo');
En este caso, nombre es un Symbol con una descripción opcional.
La descripción de un símbolo no afecta su unicidad, pero puede ser útil para la depuración.
let simbolo = Symbol('mi simbolo');
console.log(simbolo.toString()); // Imprime: Symbol(mi simbolo)
La descripción se puede obtener a través del método toString() del símbolo.
Unicidad de los Symbols
La principal característica de los símbolos su valor es siempre único y diferente del de todos los demás (incluso si dos símbolos tienen la misma descripción).
let simbolo1 = Symbol('descripcion');
let simbolo2 = Symbol('descripcion');
console.log(simbolo1 === simbolo2); // Imprime: false
En el ejemplo anterior,
simbolo1ysimbolo2son dos símbolos distintos, a pesar de que ambos tienen la misma descripción.- Es decir que cada llamada a
Symbol()ha producido un identificador único.
Usos del Tipo Symbol
Evitar sobreescritura de propiedades
Uno de los usos más comunes de los Symbols es como claves para las propiedades de objetos, para evitar que sean sobreescritas por accidente.
Vamos a verlo con un ejemplo
let objeto = {
propiedad: 'valor 1'
};
// Más adelante, otra parte del código añade una propiedad con el mismo nombre:
objeto.propiedad = 'valor 2';
console.log(objeto.propiedad); // Imprime: 'valor 2'
En este caso,
- Hemos definido un objeto literal, con la
propiedadque valor valor 1 - Posteriormente, alguien por error, sobreescribe con el valor valor 2
// Creamos un Symbol con una descripción
let simboloPropiedad = Symbol('propiedad');
let objeto = {};
// Usamos el Symbol como clave para la propiedad
objeto[simboloPropiedad] = 'valor 1';
// Más adelante, intentamos añadir otra propiedad con el mismo nombre,
// pero como usamos un Symbol, no hay sobrescritura
let otroSimbolo = Symbol('propiedad');
objeto[otroSimbolo] = 'valor 2';
// Accedemos a las propiedades usando los Symbols
console.log(objeto[simboloPropiedad]); // Imprime: 'valor 1'
console.log(objeto[otroSimbolo]); // Imprime: 'valor 2'
En este ejemplo,
- Creamos un
SymbolllamadosimboloPropiedady lo usamos como clave para una propiedad en el objetoobjeto. - Luego, en otra parte del código, creamos un nuevo
SymbolllamadootroSimbolo. Aunque ambos símbolos tienen la misma descripción (‘propiedad’), son diferentes entre sí. - Por lo tanto, cuando asignamos
'valor 2'aobjeto[otroSimbolo], no sobrescribe el valor deobjeto[simboloPropiedad], sino que crea una nueva propiedad.
Métodos y propiedades simbólicas
JavaScript incluye varios símbolos integrados que se usan como claves para métodos y propiedades especiales. Estos símbolos están definidos en el objeto Symbol.
| Símbolo | Descripción |
|---|---|
Symbol.iterator | Este símbolo se usa para definir el iterador de un objeto. |
Symbol.toStringTag | Este símbolo se usa para definir el valor de la propiedad Symbol.toStringTag |
Symbol.toStringTag que se usa para personalizar el resultado del método Object.prototype.toString().
Símbolos globales con Symbol.for()
Otro uso diferente de los Symbos ocurre con el método Symbol.for(). Este permite crear un símbolo global que es accesible en todo el entorno de ejecución.
Si intentas crear un símbolo con la misma clave, devolverá el mismo símbolo. Es decir, Symbol.for() lleva una especie de “registro global” de símbolos.
const simboloGlobal1 = Symbol.for('miSimbolo');
const simboloGlobal2 = Symbol.for('miSimbolo');
console.log(simboloGlobal1 === simboloGlobal2); // Imprime: true
En este caso,
- Creamos un símbolo global con la clave
'miSimbolo'conSymbol.for('miSimbolo'). - Al llamar nuevamente a
Symbol.for('miSimbolo'), JavaScript no crea un nuevo símbolo. - En lugar de eso, busca en el registro global de símbolos y, si ya existe un símbolo con esa clave (como
'miSimbolo'), te devuelve el mismo símbolo. - Como son el mismo símbolo, la comparación
simboloGlobal1 === simboloGlobal2devuelvetrue.
Esto es diferente de crear símbolos con Symbol(), que siempre genera un símbolo único, incluso si usas la misma descripción.
En cambio, Symbol.for() asegura que el símbolo creado sea único a nivel global, y si ya existe un símbolo con esa clave, te devolverá el mismo símbolo.
Ejemplos prácticos
Propiedades pseudo-privadas
JavaScript incorpora el concepto de propiedades privadas en 2022. Pero anteriormente, era frecuente usar Symbols como una solución “parcial” para encapsulamiento.
const propiedadPrivada = Symbol('privado');
class MiClase {
constructor(valor) {
this[propiedadPrivada] = valor;
}
obtenerValor() {
return this[propiedadPrivada];
}
}
let instancia = new MiClase(123);
console.log(instancia.obtenerValor()); // Imprime: 123
En este ejemplo,
propiedadPrivadaes un símbolo que actúa como una “pseudo”-propiedad privada de la claseMiClase.- Solo podríamos acceder a la propiedad si tenemos el símbolo accesible.
Evitar colisiones de nombres de propiedades
Los símbolos pueden ser útiles para evitar colisiones de nombres de propiedades en objetos, ya que son únicos e inmutables.
const NOMBRE = Symbol('nombre');
const persona = {
[NOMBRE]: 'Juan',
edad: 30,
};
console.log(persona[NOMBRE]); // Resultado: Juan
En este caso, NOMBRE es un Symbol utilizado como clave para el nombre de una persona en el objeto persona.
Iteración de propiedades
Aunque las propiedades de tipo Symbol no son enumerables por defecto. Es decir, que no son accesibles a través de métodos estándar como Object.keys() o for...in.
Sin embargo, podemos utilizar el método Object.getOwnPropertySymbols() para obtener todas las propiedades de tipo Symbol de un objeto.
const clave1 = Symbol('clave1');
const clave2 = Symbol('clave2');
const miObjeto = {
[clave1]: 'Valor 1',
[clave2]: 'Valor 2',
nombre: 'Objeto',
};
const symbols = Object.getOwnPropertySymbols(miObjeto);
console.log(symbols); // Resultado: [Symbol(clave1), Symbol(clave2)]
En este ejemplo, symbols contiene los Symbol utilizados como claves en el objeto miObjeto.