Ajouter une propriété à un objet qui ne vous appartient pas est une opération risquée : si une bibliothèque écrit obj.id et qu'une autre fait pareil, la seconde efface la première sans bruit.
Le symbole résout ce problème à la racine, en fournissant une clé que personne d'autre ne peut fabriquer par hasard.
Définition
Un Symbol est une valeur primitive unique et immuable, créée par l'appel Symbol(). Deux symboles ne sont jamais égaux, même créés avec la même description.
const a = Symbol("id");
const b = Symbol("id");
console.log(a === b); // false
console.log(a.description); // "id"
console.log(typeof a); // "symbol"La description ne sert qu'au débogage : elle apparaît dans les messages et dans la console, sans jamais participer à la comparaison. C'est ce qui distingue un symbole d'une chaîne, avec laquelle deux valeurs identiques sont la même clé.
Une clé de propriété discrète
Un symbole s'utilise comme clé entre crochets. La propriété existe et se lit normalement, mais elle échappe aux parcours ordinaires.
const INTERNE = Symbol("interne");
const compte = { nom: "Ada", [INTERNE]: "jeton" };
console.log(Object.keys(compte)); // [ 'nom' ]
console.log(JSON.stringify(compte)); // {"nom":"Ada"}
console.log(compte[INTERNE]); // "jeton"Ni Object (objet).keys, ni une boucle in, ni JSON.stringify ne voient cette clé. La donnée voyage avec l'objet sans polluer sa forme publique, ce qui est exactement l'usage recherché par les bibliothèques.
Les symboles bien connus
Le langage réserve quelques symboles pour brancher un objet sur ses propres mécanismes. Le plus utile est Symbol.iterator, qui rend un objet parcourable par of et dépliable par Spread (...).
const semaine = {
jours: ["lundi", "mardi", "mercredi"],
[Symbol.iterator]() {
let i = 0;
const { jours } = this;
return {
next: () =>
i < jours.length
? { value: jours[i++], done: false }
: { value: undefined, done: true },
};
},
};
for (const jour of semaine) console.log(jour);
console.log([...semaine]); // [ 'lundi', 'mardi', 'mercredi' ]Questions fréquentes
Pourquoi new Symbol() lève-t-il une erreur ?
Parce qu'un symbole est une primitive, au même titre qu'un nombre ou un booléen, et non un objet à construire. Le new lève une TypeError disant que Symbol n'est pas un constructeur. La fonction s'appelle directement.
Une propriété par symbole est-elle vraiment privée ?
Non, elle est discrète. Object.getOwnPropertySymbols les liste toutes, et qui détient le symbole lit la valeur. Pour de la confidentialité réelle, ce sont les champs privés d'une class, préfixés par un dièse, qu'il faut employer.
À quoi sert Symbol.for ?
À partager un symbole entre plusieurs morceaux de code. Symbol.for("app.id") consulte un registre global et rend toujours la même valeur, là où Symbol("app.id") en crée une nouvelle à chaque appel. À réserver aux cas où le partage est voulu.