Tutoriel présentant les nouveautés ECMAScript 6

Les objets et les tableaux

Maurice Chavelli

JavaScript existe depuis longtemps et il est resté longuement cantonné à la dynamisation des pages web. Mais depuis quelques années, il sort de ce rôle et se déploie avec efficacité dans d’autres contextes. Par exemple, son utilisation côté serveur avec node.js est un franc succès.‌

Officiellement, JavaScript se nomme ECMAScript et il est normalisé. On trouve les dernières fonctionnalités et définitions dans la norme Ecma-262.

Dans ce cours, je vous présente ES6 qui conserve l’existant (donc tout ES5 reste valable) et ajoute de nombreuses et intéressantes possibilités, en particulier les modules et les classes.‌

Ce cours n’est pas une initiation à JavaScript, mais s’adresse à ceux qui savent déjà coder avec ES5 et qui désirent aller plus loin avec les nouvelles possibilités d’ES6.

Commentez

- Titre : Tutoriel présentant les nouveautés ECMAScript 6

- Auteur : Maurice Chavelli

- Parution : 14 juillet 2019

- Licence : Copyright ® 2018 Maurice Chavelli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. ES6 : les objets

- I-A. Les initialisateurs d'objets (objets littéraux)

- I-A-1. Simplification pour les propriétés

- I-A-2. Simplification pour les méthodes

- I-A-3. Propriété calculée

- I-B. Les nouvelles méthodes pour Object

- I-B-1. Object.assign

- I-B-2. Object.is

- I-C. En résumé

- II. ES6 : les tableaux

- II-A. Création d'un tableau

- II-A-1. Array.from

- II-A-2. Array.of

- II-B. Les nouvelles méthodes des tableaux

- II-B-1. La recherche des éléments

- II-B-2. Remplir un tableau

- II-B-3. Copie superficielle

- II-C. En résumé

- III. ES6 : les tableaux typés

- III-A. Architecture

- III-A-1. Les buffers

- III-A-2. Les vues

- III-B. Lire et écrire

- III-C. Tableaux typés et tableaux classiques

- III-D. En résumé

I - ES6 : les objets

On va voir bientôt que la principale avancée de ES6 au niveau des objets est l'arrivée de la syntaxe des classes. Mais avant d'aborder ce sujet on va commencer par voir quelques nouvelles possibilités pour les objets.

I-A - Les initialisateurs d'objets (objets littéraux)

I-A-1 - Simplification pour les propriétés

Vous utilisez sans doute beaucoup d'initialisateurs d'objets de ce genre :

1. let identite = {

2. nom: "Durand",

3. prenom: "Louis",

4. caracteristiques: {

5. age: 20,

6. poids: 75

7. }

8. };

C'est une syntaxe simple et rapide.

Avec ES6 vous pouvez initialiser les propriétés avec des variables existantes :

1. let nom = "Durand";

2. let prenom = "Louis";

3. let age = 20;

4. let poids = 75;

5. let identite = {

6. nom,

7. prenom,

8. caracteristiques: {

9. age,

10. poids

11. }

12. };

I-A-2 - Simplification pour les méthodes

Avec ES5 vous déclarez une méthode ainsi :

1. let nom = "Durand";

2. let identite = {

3. nom,

4. getNom: function() {

5. return this.nom;

6. }

7. };

8. console.log(identite.getNom());  // Durand

Avec ES6 vous avez une syntaxe simplifiée (on évite function) :

1. let nom = "Durand";

2. let identite = {

3. nom,

4. getNom() {

5. return this.nom;

6. }

7. };

8. console.log(identite.getNom());  // Durand

I-A-3 - Propriété calculée

On peut maintenant avoir un nom de propriété déterminé par une expression. Il suffit d'utiliser des crochets :

1. let identifiant = "no";

2. let identite = {

3. [identifiant + "m"]: "Durand",

4. };

5. console.log(identite.nom);  // Durand

I-B - Les nouvelles méthodes pour Object

I-B-1 - Object.assign

Regardez ce code :

const identite = { nom: "Durand" };
Object.assign(identite, { prenom: "Louis" });
console.log(identite);  // {"nom":"Durand","prenom":"Louis"}

On effectue une composition d'objets en ajoutant à l'objet identite les propriétés d'un autre objet.

On ne copie que les propriétés énumérables et non héritées.

Que se passe-t-il si des propriétés ont le même nom ?

Et bien on va faire un essai :

const identite = { nom: "Durand", prenom : "Louis" };
Object.assign(identite, { prenom: "Alfred" });
console.log(identite);  // {"nom":"Durand","prenom":"Alfred"}

On a une surcharge de la propriété.

Et les accesseurs ?

1. const identite = {

2. nom: "Durand",

3. prenom: "Louis",

4. get nomComplet() { return this.nom + " " + this.prenom }

5. };

6. let copie = Object.assign({}, identite);

7. console.log(copie);  // {"nom":"Durand","prenom":"Louis","nomComplet":"Durand Louis"}

On se retrouve avec une propriété dont la valeur est celle retournée par l'accesseur.

I-B-2 - Object.is

Lorsqu'on veut comparer deux valeurs on utilise == ou ===. La seconde syntaxe est la plus sûre parce qu'elle ne se contente pas de comparer les valeurs mais aussi le type. Mais même avec cette syntaxe, on a deux petits soucis :

- -0 === +0 est considéré comme vrai ;

- NaN === NaN est considéré comme faux.

ES6 introduit la méthode is pour avoir un vrai contrôle de l'identité de deux valeurs :

1. Object.is([], []);     // false

2. Object.is(null, null); // true

3. Object.is(0, -0);      // false

4. Object.is(-0, -0);     // true

5. Object.is(NaN, 0/0);   // true

I-C - En résumé

- ES6 apporte une simplification de la syntaxe pour les propriétés et les méthodes des initialisateurs d'objets ;

- ES6 enrichit Object des méthodes assign et is.

II - ES6 : les tableaux

Les tableaux (arrays) constituent l’un des fondements de JavaScript. On ne peut pas dire qu'ils aient beaucoup évolué dans le temps bien que ES5 ait apporté quelques méthodes pour rendre leur utilisation plus simple. ES6 continue sur la lancée et apporte son lot de nouveautés. On va faire un peu le point dans ce chapitre

II-A - Création d'un tableau

Avec ES5 on a deux façons de créer un tableau :

var nombres = [2, 6, 10];
var autresNombres = new Array(5, 23, 9);

Dans les deux cas il faut lister tous les éléments.

ES6 nous offre deux nouvelles façons de créer un tableau

II-A-1 - Array.from

La méthode Array.from permet de créer un nouveau tableau à partir d'un objet itérable ou « qui ressemble » à un tableau :

1. const commeUnTableau = { 0: "Durand", 1: "Louis", length: 2 };

3. const tableau = Array.from(commeUnTableau);

4. for (const item of tableau) {

5. console.log(item);

6. }

L'objet commeUnTableau a des éléments indexés et une propriété length.

Il ressemble donc à un tableau mais ne dispose d'aucune des méthodes correspondantes

En le transformant en tableau, on peut maintenant le parcourir.

Un autre exemple d'utilisation est celui de l'objet arguments.

1. function f() {

2. console.log(Array.from(arguments));  // ["un","deux","trois","quatre"]

3. }

4. f('un', 'deux', 'trois', 'quatre');

On peut ajouter un argument pour effectuer un traitement sur les éléments :

1. function f() {

2. console.log(Array.from(arguments, x => 2 * x));  // [2,4,6]

3. }

4. f(1, 2, 3);

J'ai utilisé une fonction fléchée puisque maintenant vous les connaissez !

II-A-2 - Array.of

D'après vous, qu'obtenez-vous avec cette déclaration de tableau ?

let tableau = new Array(2);

Voilà le résultat :

console.log(items); //  [null,null]

Vous aviez deviné ?

Lorsqu'on passe juste un argument avec une valeur numérique au constructeur, ça donne juste la longueur du tableau.

Et maintenant dans ce cas ?

let tableau = new Array("2");

Cette fois on obtient un tableau avec juste l'élément transmis.

Vous avouerez que c'est quand même un peu confus !

C'est là qu'intervient la nouvelle méthode Array.of :

let tableau = Array.of(2);
console.log(tableau);  // [2]

On se contente de transmettre les éléments qu'on veut dans le tableau.

II-B - Les nouvelles méthodes des tableaux

II-B-1 - La recherche des éléments

ES5 n'est pas très bien équipé pour faire des recherches dans un tableau. On a bien les méthodes indexOf et lastIndexOf, mais leur action est limitée.

Avec ES6 arrivent les méthodes find et findIndex qui ouvrent de nouvelles possibilités.

La différence entre find et findIndex est que la première renvoie une valeur, alors que la seconde renvoie un index, sinon c'est exactement le même fonctionnement.

On doit passer comme argument une fonction de rappel qui effectue un test sur les valeurs du tableau :

1. let valeur = [1, 3, 2].find(x => x > 2);

2. let index = [1, 3, 2].findIndex(x => x > 2);

3. console.log(valeur);  // 3

4. console.log(index);  // 1

Et quand on ne trouve pas, voilà les valeurs retournées :

1. let valeur = [1, 3, 2].find(x => x > 3);

2. let index = [1, 3, 2].findIndex(x => x > 3);

3. console.log(valeur);  // undefined

4. console.log(index);  // -1

II-B-2 - Remplir un tableau

La méthode fill permet de remplacer toutes les valeurs d'un tableau par une certaine valeur. On peut limiter l'action avec un index de départ et un index d'arrivée :

console.log([1, 2, 3].fill(0));         // [0,0,0]
console.log([1, 2, 3].fill(0, 1));      // [1,0,0]
console.log([1, 2, 3].fill(0, 1 , 2));  // [1,0,3]

II-B-3 - Copie superficielle

La méthode copyWithin effectue une copie superficielle d'une partie d'un tableau sur lui-même. On dispose de trois arguments :

- cible : index de début de la copie (peut être négatif) ;

- début : index de début de la partie à copier (optionnel, peut être négatif) ;

- fin : index de fin de la partie à copier (optionnel, peut être négatif).

Voici quelques exemples :

1. console.log([1, 2, 3, 4].copyWithin(-1));        // [1,2,3,1]

2. console.log([1, 2, 3, 4].copyWithin(2));         // [1,2,1,2]

3. console.log([1, 2, 3, 4].copyWithin(1, 3));      // [1,4,3,4]

4. console.log([1, 2, 3, 4].copyWithin(1, 2, 3));   // [1,3,3,4]

II-C - En résumé

- avec ES6, on peut créer un tableau à partir d'un objet itérable ou « qui ressemble » à un tableau avec la méthode Array.from ;

- avec ES6, on peut créer un tableau de manière plus sûre, avec la méthode Array.of ;

- ES6 introduit les méthodes find et findIndex pour effectuer une recherche dans un tableau avec une fonction de rappel ;

- avec ES6 on peut remplir un tableau avec la méthode fill ou faire une copie superficielle avec la méthode copyWithin.

III - ES6 : les tableaux typés

Les tableaux typés ne sont pas une nouveauté d'ES6. Il concernent uniquement les valeurs numériques. Ils trouvent leur source dans WebGL qui permet de gérer de la 3D de façon dynamique sur une page web. Comme les calculs arithmétiques avec JavaScript étaient trop lents (utilisation de données en 64 bits avec virgule flottante) les tableaux typés ont été créés avec une spécification déjà bien prise en charge par les navigateurs. ES6 reprend ce concept en l'améliorant comme on va le voir dans ce chapitre.

III-A - Architecture

Les tableaux typés servent à manipuler des données binaires : images, canvas, API (XMLHttpRequest, WebSockets, files…)etc.

On a deux objets spécifiques :

- les buffers : ils contiennent les données ;

- les vues : elles permettent de manipuler les données stockées par les buffers.

III-A-1 - Les buffers

Un buffer est un espace mémoire qui contient un certain nombre d'octets de données. Pour créer un buffer c'est tout simple :

let buffer = new ArrayBuffer(4);

Ici on a créé un buffer de 4 octets.

III-A-2 - Les vues

Une vue est une interface pour manipuler les données stockées dans un buffer : lecture, écriture.

Il existe une vue générique qu'on crée avec DataView :

let buffer = new ArrayBuffer(4);
let vue = new DataView(buffer);

On peut alors manipuler les données du buffer avec cette vue.

Mais il existe aussi neuf vues spécifiques à certains types de données :

Nom

Taille en octets

Description

Int8Array

1

Entier signé en complément à deux sur 8 bits

Uint8Array

1

Entier non signé sur 8 bits

Uint8ClampedArray

1

Entier non signé sur 8 bits (compris entre 0 et 255)

Int16Array

2

Entier signé en complément à deux sur 16 bits

Uint16Array

2

Entier non signé sur 16 bits

Int32Array

4

Entier signé en complément à deux sur 32 bits

Uint32Array

4

Entier non signé sur 32 bits

Float32Array

4

Nombre flottant sur 32 bits selon la représentation IEEE

Float64Array

8

Nombre flottant sur 64 bits selon la représentation IEEE

On peut donc créer des vues qui gèrent un certain type de données :

let buffer = new ArrayBuffer(8);
let vue = new Uint8Array(buffer);

Ici on a une vue pour gérer des entiers non signés sur 8 bits. On peut en mettre 8 dans le buffer.

Une vue ne gère pas forcément tout le buffer, elle peut être partielle.

let buffer = new ArrayBuffer(8);
let vue = new DataView(buffer, 4, 2);

On a ajouté deux arguments :

- l'offset : ici on a 4, donc on commence au quatrième octet ;

- le nombre d'octets à prendre en compte : ici on a 2, on gère donc les octets de 4 à 5.

III-B - Lire et écrire

Une fois qu'on a un buffer et une ou plusieurs vues, on peut lire et écrire des données. Pour chacun des types de données, on a une méthode set et une méthode get. Par exemple, pour Int8Array, on a les méthodes setInt8 et getInt8. Voici un exemple :

1. let buffer = new ArrayBuffer(3);

2. let vue = new DataView(buffer);

3. vue.setInt8(0, -2);

4. vue.setInt16(1, 400);

5. console.log(vue.getInt8(0)); // -2

6. console.log(vue.getUint16(1)); // 400

Le premier argument est l'offset et le second la valeur.

Mais puisqu'on a des tableaux, on peut directement utiliser la syntaxe avec les crochets :

1. let buffer = new ArrayBuffer(2);

2. let vue8 = new Uint8Array(buffer);

3. vue8[0] = 12;

4. vue8[1] = 112

5. console.log(vue8[0]); // 12

6. console.log(vue8[1]); // 112

III-C - Tableaux typés et tableaux classiques

On peut se demander quelles sont les similarités et différences entre les tableaux typés et les tableaux classiques…

Vous pouvez utiliser pratiquement toutes les méthodes des tableaux classiques : keys, find, slice, join, reverse…

Évidemment, les tableaux typés sont itérables comme les tableaux classiques.

Mais attention les tableaux typés n'héritent pas de Array !

Donc si vous utilisez isArray() le résultat sera négatif.

D'autre part, les tableaux typés ont une dimension fixe alors que les tableaux classiques adaptent leur taille au contenu.

Enfin, certaines méthodes n'existent pas : concat, pop, push, shift, splice et unshift.

Par contre, les tableaux typés possèdent les méthodes set et subarray qui ne sont pas disponibles pour les tableaux classiques.

Cet article n'est qu'une courte introduction aux tableaux typés. Si vous voulez en savoir plus, consultez par exemple l'excellente documentation MDN.

III-D - En résumé

- ES6 implémente les tableaux typés qui existaient déjà en leur apportant de nouvelles possibilités ;

- l'architecture des tableaux typés est fondée sur deux éléments : les buffers et les vues ;

- il existe neuf types de données mémorisables dans les tableaux typés ;

- on peut manipuler les données d'un tableaux typé presque comme pour un tableau classique, il y a toutefois certaines différences avec des méthodes en plus et d'autres en moins.‌