Hacks pour créer des tableaux JavaScript

Conseils utiles pour créer et cloner des tableaux en JavaScript.

Un aspect très important de chaque langage de programmation est les types de données et les structures disponibles dans le langage. La plupart des langages de programmation fournissent des types de données pour représenter et travailler avec des données complexes. Si vous avez travaillé avec des langages comme Python ou Ruby, vous devriez avoir vu des types de données tels que des listes , des ensembles , des tuples , des hachages , des dictionnaires , etc.

En JavaScript, il n'y a pas tellement de types de données complexes - vous avez simplement des tableaux et des objets . Cependant, dans ES6, quelques types de données et structures ont été ajoutés au langage, tels que des symboles , des ensembles et des cartes .

Les tableaux en JavaScript sont des objets de type liste de haut niveau avec une propriété length et des propriétés integer comme index.

Dans cet article, je partage quelques hacks pour créer de nouveaux tableaux JavaScript ou cloner ceux déjà existants.

Création de tableaux: le constructeur de tableaux

La méthode la plus courante pour créer des tableaux utilise la syntaxe littérale de tableau , qui est très simple. Cependant, lorsque vous souhaitez créer dynamiquement des tableaux, la syntaxe littérale de tableau n'est pas toujours la meilleure méthode. Une autre méthode consiste à utiliser le Arrayconstructeur.

Voici un simple extrait de code montrant l'utilisation du Arrayconstructeur.

À partir de l'extrait de code précédent, nous pouvons voir que le Arrayconstructeur crée des tableaux différemment selon les arguments qu'il reçoit.

Nouveaux tableaux: avec une longueur définie

Regardons de plus près ce qui se passe lors de la création d'un nouveau Arrayd'une longueur donnée. Le constructeur définit simplement la lengthpropriété du tableau à la longueur donnée, sans définir les clés.

À partir de l'extrait de code ci-dessus, vous pourriez être tenté de penser que chaque clé du tableau a été définie sur la valeur undefined. Mais la réalité est que ces clés n'ont jamais été définies (elles n'existent pas).

L'illustration suivante le rend plus clair:

Cela rend inutile d'essayer d'utiliser l'une des méthodes d'itération de tableau telles que map(), filter()ou reduce()de manipuler le tableau. Disons que nous voulons remplir chaque index du tableau avec le nombre 5comme valeur. Nous tenterons ce qui suit:

Nous pouvons voir que cela map()n'a pas fonctionné ici, car les propriétés d'index n'existent pas sur le tableau - seule la lengthpropriété existe.

Voyons différentes manières de résoudre ce problème.

1. Utilisation de Array.prototype.fill ()

La fill()méthode remplit tous les éléments d'un tableau d'un index de début à un index de fin avec une valeur statique. L'index de fin n'est pas inclus. Vous pouvez en savoir plus fill()ici.

Notez que fill()cela ne fonctionnera que dans les navigateurs prenant en charge ES6.

Voici une illustration simple:

Ici, nous avons pu remplir tous les éléments de notre tableau créé avec 5. Vous pouvez définir n'importe quelle valeur statique pour différents index du tableau à l'aide de la fill()méthode.

2. Utilisation de Array.from ()

La Array.from()méthode crée une nouvelle Arrayinstance copiée peu profonde à partir d'un objet de type tableau ou itérable. Vous pouvez en savoir plus Array.from()ici.

Notez que Array.from()cela ne fonctionnera que dans les navigateurs prenant en charge ES6.

Voici une illustration simple:

Ici, nous avons maintenant de vraies undefinedvaleurs définies pour chaque élément du tableau en utilisant Array.from(). Cela signifie que nous pouvons maintenant continuer et utiliser des méthodes comme .map()et .filter()sur le tableau, puisque les propriétés d'index existent maintenant.

Une autre chose à noter Array.from()est qu'il peut prendre un deuxième argument, qui est une fonction de carte. Il sera appelé sur chaque élément du tableau. Cela rend les appels redondants .map()après Array.from().

Voici un exemple simple:

3. Utilisation de l'opérateur d'épandage

L' opérateur de diffusion( ...), ajouté dans ES6, peut être utilisé pour répartir les éléments du tableau, en définissant les éléments manquants sur une valeur de undefined. Cela produira le même résultat qu'un simple appel Array.from()avec juste le tableau comme seul argument.

Voici une illustration simple de l'utilisation de l'opérateur de diffusion:

Vous pouvez continuer et utiliser des méthodes comme .map()et .filter()sur le tableau, puisque les propriétés d'index existent maintenant.

Utilisation de Array.of ()

Tout comme nous l'avons vu avec la création de nouveaux tableaux à l'aide du Arrayconstructeur ou de la fonction, Array.of()se comporte de manière très similaire. En fait, la seule différence entre Array.of()et Arrayréside dans la manière dont ils gèrent un seul argument entier qui leur est passé.

While Array.of(5)crée un nouveau tableau avec un seul élément, 5et une propriété length de 1, Array(5)crée un nouveau tableau vide avec 5 emplacements vides et une propriété length de 5.

var array1 = Array.of(5); // [5] var array2 = Array(5); // Array(5) {length: 5}

Outre cette différence majeure, Array.of()se comporte comme le Arrayconstructeur. Vous pouvez en savoir plus Array.of()ici.

Notez que Array.of()cela ne fonctionnera que dans les navigateurs prenant en charge ES6.

Conversion en tableaux: Array-likes et itérables

Si vous écrivez des fonctions JavaScript depuis assez longtemps, vous devriez déjà connaître l' argumentsobjet - qui est un objet de type tableau disponible dans chaque fonction pour contenir la liste des arguments reçus par la fonction. Bien que l' argumentsobjet ressemble beaucoup à un tableau, il n'a pas accès aux Array.prototypeméthodes.

Avant ES6, vous voyiez généralement un extrait de code comme celui-ci lorsque vous tentiez de convertir l' argumentsobjet en tableau:

Avec Array.from()ou l'opérateur spread, vous pouvez facilement convertir n'importe quel objet de type tableau en tableau. Par conséquent, au lieu de faire cela:

var args = Array.prototype.slice.call(arguments);

vous pouvez faire l'une des deux:

// Using Array.from() var args = Array.from(arguments); // Using the Spread operator var args = [...arguments];

Celles-ci s'appliquent également aux itérables, comme indiqué dans l'illustration suivante:

Étude de cas: fonction de plage

Comme étude de cas avant de continuer, nous allons créer une range()fonction simple pour implémenter le nouveau hack de tableau que nous venons d'apprendre. La fonction a la signature suivante:

range(start: number, end: number, step: number) => Array

Voici l'extrait de code:

Dans cet extrait de code, nous avions l'habitude Array.from()de créer le nouveau tableau de plage de longueur dynamique, puis de le remplir de nombres incrémentés séquentiellement en fournissant une fonction de mappage.

Notez que l'extrait de code ci-dessus ne fonctionnera pas pour les navigateurs sans prise en charge ES6, sauf si vous utilisez des polyfills.

Voici quelques résultats de l'appel de la range()fonction définie dans l'extrait de code ci-dessus:

Vous pouvez obtenir une démonstration de code en direct en exécutant le stylo suivant sur Codepen :

Cloner des tableaux: le défi

En JavaScript, les tableaux et les objets sont des types de référence. Cela signifie que lorsqu'une variable se voit attribuer un tableau ou un objet, ce qui est assigné à la variable est une référence à l'emplacement en mémoire où le tableau ou l'objet a été stocké.

Les tableaux, comme tous les autres objets en JavaScript, sont des types de référence. Cela signifie que les tableaux sont copiés par référence et non par valeur.

Le stockage des types de référence de cette manière a les conséquences suivantes:

1. Les tableaux similaires ne sont pas égaux.

Ici, nous voyons que même si array1et array2contiennent apparemment les mêmes spécifications de tableau, elles ne sont pas égales. Cela est dû au fait que la référence à chacun des tableaux pointe vers un emplacement différent en mémoire.

2. Les tableaux sont copiés par référence et non par valeur.

Ici, nous essayons de copier array1vers array2, mais ce que nous faisons essentiellement est de pointer array2vers le même emplacement en mémoire que celui array1vers lequel pointe. Par conséquent, les deux array1et array2pointent vers le même emplacement dans la mémoire et sont égaux.

L'implication de ceci est que lorsque nous apportons une modification à array2en supprimant le dernier élément, le dernier élément de est array1également supprimé. En effet, la modification a été réellement apportée au tableau stocké en mémoire, alors que array1et ne array2sont que des pointeurs vers le même emplacement en mémoire où le tableau est stocké.

Clonage de tableaux: les astuces

1. Utilisation de Array.prototype.slice ()

La slice()méthode crée une copie superficielle d'une partie d'un tableau sans modifier le tableau. Vous pouvez en savoir plus slice()ici.

L'astuce consiste à appeler slice()soit avec 0comme seul argument, soit sans aucun argument du tout:

// with O as only argument array.slice(0); // without argument array.slice();

Voici une illustration simple du clonage d'un tableau avec slice():

Ici, vous pouvez voir qu'il array2s'agit d'un clone de array1avec les mêmes éléments et la même longueur. Cependant, ils pointent vers différents emplacements de la mémoire et, par conséquent, ne sont pas égaux. Vous remarquez également que lorsque nous apportons une modification à array2en supprimant le dernier élément, array1reste inchangé.

2. Utilisation de Array.prototype.concat ()

La concat()méthode est utilisée pour fusionner deux ou plusieurs tableaux, ce qui donne un nouveau tableau, tandis que les tableaux d'origine restent inchangés. Vous pouvez en savoir plus concat()ici.

L'astuce consiste à appeler concat()soit avec un tableau vide ( []) comme argument, soit sans aucun argument du tout:

// with an empty array array.concat([]); // without argument array.concat();

Le clonage d'un tableau avec concat()est assez similaire à l'utilisation slice(). Voici une illustration simple du clonage d'un tableau avec concat():

3. Utilisation de Array.from ()

Comme nous l'avons vu précédemment, Array.from()peut être utilisé pour créer un nouveau tableau qui est une copie superficielle du tableau d'origine. Voici une illustration simple:

4. Utilisation de la destruction des baies

Avec ES6, nous avons des outils plus puissants dans notre boîte à outils tels que la déstructuration , la diffusionopérateur , fonctions fléchées , etc. La destruction est un outil très puissant pour extraire des données de types complexes tels que des tableaux et des objets.

L'astuce consiste à utiliser une technique appelée paramètres de repos, qui implique une combinaison de déstructuration de tableau et d'opérateur de propagation, comme indiqué dans l'extrait de code suivant:

let [...arrayClone] = originalArray;

L'extrait de code ci-dessus crée une variable nommée arrayClonequi est un clone du originalArray. Voici une illustration simple du clonage d'un tableau à l'aide de la déstructuration de tableau:

Clonage: peu profond contre profond

Toutes les techniques de clonage de tableau que nous avons explorées jusqu'à présent produisent une copie superficielle du tableau. Ce ne sera pas un problème si le tableau ne contient que des valeurs primitives. Cependant, si le tableau contient des références d'objets imbriqués, ces références resteront intactes même lorsque le tableau est cloné.

En voici une démonstration très simple:

Notez que la modification du tableau imbriqué dans a array1également modifié le tableau imbriqué dans array2et vice-versa.

La solution à ce problème consiste à créer une copie complète du tableau et il existe plusieurs façons de le faire.

1. La technique JSON

Le moyen le plus simple de créer une copie complète d'un tableau consiste à utiliser une combinaison de JSON.stringify()et JSON.parse().

JSON.stringify()convertit une valeur JavaScript en une chaîne JSON valide, tandis que JSON.parse()convertit une chaîne JSON en une valeur ou un objet JavaScript correspondant.

Voici un exemple simple:

La technique JSON présente certains défauts, en particulier lorsque des valeurs autres que des chaînes, des nombres et des booléens sont impliquées.

Ces failles dans la technique JSON peuvent être principalement attribuées à la manière dont la JSON.stringify()méthode convertit les valeurs en chaîne JSON.

Voici une simple démonstration de cette faille en essayant JSON.stringify()une valeur contenant une fonction imbriquée.

2. Aide à la copie approfondie

Une alternative viable à la technique JSON sera d'implémenter votre propre fonction d'assistance de copie profonde pour le clonage des types de référence, qu'il s'agisse de tableaux ou d'objets.

Voici une fonction de copie profonde très simple et minimaliste appelée deepClone:

Maintenant, ce n'est pas la meilleure des fonctions de copie en profondeur, comme vous le verrez bientôt avec certaines bibliothèques JavaScript - cependant, elle effectue une copie en profondeur dans une assez bonne mesure.

3. Utilisation des bibliothèques JavaScript

La fonction d'aide à la copie approfondie que nous venons de définir n'est pas assez robuste pour cloner tous les types de données JavaScript qui peuvent être imbriquées dans des objets ou des tableaux complexes.

Les bibliothèques JavaScript comme Lodash et jQuery fournissent des fonctions utilitaires de copie profonde plus robustes avec prise en charge de différents types de données JavaScript.

Voici un exemple qui utilise _.cloneDeep()de la bibliothèque Lodash:

Voici le même exemple mais en utilisant $.extend()la bibliothèque jQuery:

Conclusion

Dans cet article, nous avons pu explorer plusieurs techniques pour créer dynamiquement de nouveaux tableaux et cloner ceux déjà existants, y compris la conversion d'objets de type tableau et d'itérables en tableaux.

Nous avons également vu comment certaines des nouvelles fonctionnalités et améliorations introduites dans ES6 peuvent nous permettre d'effectuer efficacement certaines manipulations sur des tableaux.

Nous avons utilisé des fonctionnalités telles que la déstructuration et l'opérateur de diffusion pour le clonage et la diffusion de tableaux. Vous pouvez en savoir plus sur la déstructuration dans cet article.

Applaudissez et suivez

Si vous avez trouvé cet article perspicace, vous êtes libre de donner quelques applaudissements si cela ne vous dérange pas.

Vous pouvez également me suivre sur Medium (Glad Chinda) pour des articles plus perspicaces qui pourraient vous être utiles. Vous pouvez également me suivre sur Twitter (@gladchinda).

Bon piratage…