logo

 

Road to ES2023 : Fonctions non-modifiantes sur les tableaux

Adikts - Road to ES2023

Road to ES2023 : Fonctions non-modifiantes sur les tableaux

La spécification ECMAScript, derrière le langage Javascript, voit chaque année, depuis 2015, la sortie d’une nouvelle version. La version 2023 devrait sortir d’ici quelques mois, et on connait déjà quelques unes de ses fonctionnalités. Ainsi, depuis novembre 2022, Adikts vous propose, sur son blog, la série Road to ES2023, revenant au fil des propositions sur les futurs ajouts d’ES2023. Après deux articles, consacrés à Array.prototype.findLast et Array.prototype.findLastIndex, puis à la syntaxe Hashbang, c’est maintenant sur une proposition visant à ajouter au prototype de Array des fonctions de traitement non-modifiantes sur lesquelles nous allons nous pencher.

Disclaimer : Dans la mesure où la spécification ES2023 n’est pas encore officiellement annoncée, 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 Javascript, il existe, sur le prototype de Array (ainsi que sur quelques autres prototypes dérivés, notamment TypedArray), des fonctions permettant de modifier un tableau, pour y appliquer un traitement fréquemment utile, notamment le trier, l’inverser, en retirer des éléments, ou n’en conserver que quelques uns. Il s’agit de Array.prototype.sort, Array.prototype.reverse, et Array.prototype.splice. Ces fonctions ont cependant une limite : elles modifient le tableau sur lequel elles sont appelées, ce qui peut être piégeux quand on est habitué à d’autres fonctions comme Array.prototype.map, qui ne sont pas modifiantes. Cela va également à l’encontre des principes de programmation fonctionnelle qui gagnent en popularité, et peut créer des effets de bord, tels que la modification d’un tableau passé en paramètre.

const people = ['Didier', 'Yan', 'David', 'Jeremy']

function sortUsers(users) {
	return users.sort()
}

sortUsers(people) // ['David', 'Didier', 'Jeremy', 'Yan'], le résultat attendu
people // ['David', 'Didier', 'Jeremy', 'Yan'], résultat qui n'était pas vraiment prévu

Une solution pour éviter cet inconvénient est de cloner le tableau avant de le traiter, mais cela oblige à rajouter un appel à Array.from, pas forcément clair, et dont l’oubli est facile.

const people = ['Didier', 'Yan', 'David', 'Jeremy']

function sortUsers(users) {
	return Array.from(users).sort()
}

sortUsers(people) // ['David', 'Didier', 'Jeremy', 'Yan'], le résultat attendu
people // ['Didier', 'Yan', 'David', 'Jeremy'], aucun effet de bord !

Le but de cette proposition, devant faire partie intégrante de la spécification de ES2023, est donc d’ajouter des fonctions faisant les mêmes traitements que sort, reverse et splice, mais en créant à chaque fois un nouveau tableau, permettant un meilleur respect des principes de programmation fonctionnelle, et d’éviter des effets de bord. Le nom de ces fonctions est assez logique : Array.prototype.toSorted, Array.prototype.toReversed et Array.prototype.toSpliced. Quant à Array.prototype.with, elle offre une alternative à l’opérateur [], pour changer une valeur en particulier grâce à son index.

Utilisation

Ces fonctions sont disponibles directement au sein du prototype de Array, comme les fonctions d’origine, et ont la même signature et le même fonctionnement que celles-ci.

const people = ['Didier', 'Yan', 'David', 'Jeremy']
// Équivalent non-modifiant de sort()
people.toSorted() // => ['David', 'Didier', 'Jeremy', 'Yan']
// Équivalent non-modifiant de reverse()
people.toReversed() // => ['Jeremy', 'David', 'Yan', 'Didier']
// Équivalent non-modifiant de splice()
people.toSpliced(0, 2, 'Samson') // => ['Samson', 'David', 'Jeremy']
// Équivalent non-modifiant de l'opérateur []
people.with(1, 'Dorra') // => ['Didier', 'Dorra', 'David', 'Jeremy']

Comme on peut le constater au sein de ce bloc de code, le tableau n’est pas altéré, et conserve ses éléments et son ordre, nous permettant de faire des traitements sans risque d’effet de bord, avec une approche fonctionnelle, sans recourir à la copie systématique du tableau d’origine.

Évidemment, ces fonctions sont également disponibles sur les types dérivés de TypedArray, comme Uint8Array ou BigInt64Array, à l’exception de toSpliced, puisque splice n’existe pas sur ces types.

const numbers = new Uint8Array([0b0100_0001, 0b0110_0100, 0b0110_1001, 0b0110_1011, 0b0111_0100, 0b0111_0011])
numbers.toSorted((a, b) => a - b) // => [0b0100_0001, 0b0110_0100, 0b0110_1001, 0b0110_1011, 0b0111_0011, 0b0111_0100]
numbers.toReversed() // => [0b0111_0011, 0b0111_0100, 0b0110_1011, 0b0110_1001, 0b0110_0100, 0b0100_0001]
numbers.toSpliced // => undefined
numbers.with(5, 0b0001_1110) // => [0b0100_0001, 0b0110_0100, 0b0110_1001, 0b0110_1011, 0b0111_0100, 0b0001_1110]

Compatibilité

Contrairement à d’autres, cette proposition est encore assez marginalement disponible, même si les implémentations livrées sont de plus en plus nombreuses. C’est notamment le cas de Chrome et de ses dérivés, depuis Chrome 110 et le moteur v8 11.0, sortis en décembre 2022. Sur Firefox, la fonctionnalité nécessite un flag pour être utilisée, et n’est donc pas disponible pour le grand public. Chez Safari également, le support se fait attendre. Côté node.js, le support est présent à partir de la version 20, sortie le 18 avril 2023, qui embarque la version 11.3 du moteur v8. Elle sera également certifiée LTS à partir du 10 octobre.

Faute de support natif, es-shims permet d’utiliser ces fonctionnalités dans un environnement supportant ES3 (donc potentiellement jusqu’à Internet Explorer). core.js permet également d’apporter ce support dans les environnements qui ne l’auraient pas. Dans tous les cas, le support de cette fonctionnalité ne saurait tarder étant donné qu’elle arrivera dans la spécification officielle dans les mois à venir.

Il s’agit de la troisième fonctionnalité qui rejoindra la spécification ECMAScript 2023 dans quelques mois. Maintenant que la spécification est gelée, nous savons déjà qu’une dernière fonctionnalité devrait y être ajoutée, que nous vous résumerons prochainement au sein de la série Road to ES2023. Enfin, nous vous proposerons un article récapitulatif des nouveautés d’ECMAScript 2023 dans les semaines à venir, afin de faire le point sur les dernières actualités du langage. Pour ne rien rater de ces articles, continuez à suivre le blog Adikts, et n’hésitez pas à vous abonner à la page LinkedIn !