logo

 

Road to ES2023 : Ajout des symboles comme clé des WeakMaps

Adikts - Road to ES2023

Road to ES2023 : Ajout des symboles comme clé des WeakMaps

En 2023, comme chaque année depuis 2015, une nouvelle version de la spécification ECMAScript, qui normalise le langage que nous connaissons sous le nom de JavaScript, sera disponible. Sobrement appelée ECMAScript 2023, elles apportera plusieurs fonctionnalités au langage, que nous avions déjà traitées sur ce blog (telles que les fonctions non-modifiantes sur les tableaux), dans le cadre de notre série Road to ES2023. La dernière fonctionnalité qui devrait être ajoutée à la spécification est la proposition consistant à permettre l’utilisation des symboles comme clé des WeakMaps, et ce sera le sujet de cet article, qui devrait être le dernier de notre série !

Disclaimer : Dans la mesure où la spécification ES2023 n’est pas encore officiellement annoncée, même si elle est gelée depuis début avril, il n’est pas impossible que cette fonctionnalité ne fasse finalement pas partie de cette version d’ECMAScript, par exemple dans le cas où un problème serait identifié tardivement. C’est très improbable, en particulier dans le cas des petites propositions, mais tant que la spécification n’est pas officielle, des changements peuvent arriver.

Contenu

Contexte

Dans les types primitifs de Javascript, depuis ES2015, il existe le type Symbol. Parfois méconnu, il permet de définir une valeur unique, un Symbol ne pouvant être égal qu’à lui-même, même si deux symboles peuvent avoir le même description. Ils servent à rendre disponible une clé unique pour un objet, sans risque de collision, mais ils sont également utilisés dans l’implémentation de quelques aspects du langage (comme les itérables ou l’opérateur instanceof)

const symbol1 = Symbol();
const symbol2 = Symbol();
const symbol3 = Symbol('description');
const symbol4 = Symbol('description');

symbol1 === symbol2 // false
symbol1 === symbol1 // true
symbol3 === symbol4 // false
symbol4 === symbol4 // true

Également introduits avec ES2015, on trouve la WeakMap parmi les différents types de collections de Javascript. Cette collection permet, comme toute autre map, d’associer une valeur à une clé. Dans la WeakMap, cependant, la clé, jusqu’à présent, devait nécessairement être un objet. La WeakMap présente ainsi quelques spécificités, notamment le fait qu’un objet défini comme une clé peut être nettoyé par le garbage collector de Javascript s’il s’agit de son unique référence. Cela permet de définir des valeurs liées à un objet qui n’ont de sens que si cet objet existe, sans surcharger la mémoire, ni avoir des temps d’accès trop longs.

En pratique, elles sont utilisées pour étendre un objet sans modifier son comportement natif, ni perturber le nettoyage de la mémoire. Cela peut également permettre d’implémenter des attributs réellement privés dans un objet sans utiliser la syntaxe rendue disponible dans ES2022.

Seulement, ces WeakMaps n’autorisent que des objets à être utilisés comme clé, et pas les symboles, qui présentent pourtant des propriétés similaires, notamment leur unicité, et la possibilité de les supprimer clé et valeur une fois la dernière référence disparue. C’est ce que cette dernière proposition intégrée à ES2023 cherche à améliorer.

Utilisation

Très simplement, cette proposition permet de prendre en charge les Symbol comme clé pour une WeakMap, comme vous avez pu le comprendre :

const weakMap = new WeakMap();
const password = Symbol();

weakMap.set(password, 'sup3rS3cr3tP4ssw0rd');
weakMap.get(password); // 'sup3rS3cr3tP4ssw0rd'

Si les cas d’utilisation sont peu nombreux, cette nouvelle possibilité s’intègre bien avec des propositions qui devraient intégrer les futures versions d’ECMAScript, telles que les Tuple et Record ou les Shadowrealm, ces derniers ne permettant pas d’envoyer un objet au code exécuté dans un realm, mais autorisant les primitives telles que les Symbol.

Cependant, du fait de la nature spécifique de WeakMap, il est impossible d’utiliser des Symbol déclarés dans le registre global en utilisant la fonction Symbol.for.

const weakMap = new WeakMap();
const password = Symbol.for('password');

weakMap.set(password, 'sup3rS3cr3tP4ssw0rd'); // TypeError : Invalid value used as weak map key at WeakMap.set

Cela s’explique par le fait que les clés et les valeurs de la WeakMap sont censées pouvoir être jetables quand la dernière référence à la clé disparaît dans le programme, mais le fonctionnement de Symbol.for ne permet pas ce fonctionnement, car la fonction peut faire réapparaître un Symbol dont la référence aurait disparue, causant alors un problème pour accéder à la valeur définie.

En revanche, même si ça n’a pas toujours de sens, les Symbol définis par le langage peuvent être utilisés, mais ne seront jamais nettoyés par le garbage collector, assez logiquement :

const weakMap = new WeakMap();

weakMap.set(Symbol.iterator, 'itérateur');
weakMap.get(Symbol.iterator); // 'itérateur'

Compatibilité

Comme pour les fonctions non-modifiantes sur les tableaux, cette fonctionnalité a un support relativement récent, puisqu’elle est disponible seulement depuis Chrome 108 (et donc Edge 108), Safari 16.4 et Opera 94, sortis en fin d’année 2022. Fait surprenant, Firefox est le seul navigateur « vivant » à ne pas encore le prendre en charge dans sa dernière version (113, à l’heure où j’écris ces lignes), puisque l’adaptation de son moteur Javascript SpiderMonkey demande encore du développement. Cela devrait, toutefois, arriver dans les prochaines versions.

Du côté de Node.js, le support est, là-aussi, assez récent, puisqu’il a fallu attendre Node.js 20, sorti en avril, pour pouvoir utiliser les Symbol comme clés de WeakMap. Ce n’est donc pas possible dans l’actuelle version LTS (Node.js 18), mais Node.js 20 sera certifiée LTS dès octobre, il n’y a donc plus beaucoup à attendre pour utiliser cette fonction en production.

Pour les polyfills, puisqu’il s’agit d’une adaptation du comportement des WeakMap plutôt que d’une nouvelle fonction, il n’existe pas vraiment de solution, vous devrez donc attendre que le support s’étende si vous en avez besoin, notamment côté front.

Cette fonctionnalité est donc la quatrième et dernière fonctionnalité qui devrait être ajoutée à la ECMAScript dans sa version 2023, qui devrait être officiellement annoncée dès le mois de juin ! Pour savoir quelles sont les autres fonctionnalités dans les détails, nous vous invitons à consulter les 3 articles précédents (sur la recherche dans un tableau en partant de la fin, le support de la syntaxe Hashbang et les fonctions non-modifiantes sur les tableaux), et pour ne rien rater des prochains articles, suivez le blog Adikts, et pensez à vous abonner à la page LinkedIn !