Dans la première partie de ce cours vous avez déjà pu vous initier de manière basique aux tableaux. Ce que vous y avez appris vous a sûrement suffi jusqu'à présent, mais il faut savoir que les tableaux possèdent de nombreuses méthodes qui vous sont encore inconnues et qui pourtant pourraient vous aider facilement à traiter leur contenu. Dans ce chapitre nous allons donc étudier de manière avancée l'utilisation des tableaux.
L'objetArray
est à la
base de tout tableau. Il possède toutes les méthodes et les propriétés nécessaires à l'utilisation et à la
modification des tableaux. Précisons que cet objet ne concerne que les tableaux itératifs, les objets littéraux ne
sont pas des tableaux, ce sont des objets, tout simplement !
Cet objet peut être instancié de trois manières différentes. Cependant, gardez bien à l'esprit que l'utilisation de son type primitif est bien préférable à l'instanciation de son objet. Nous n'abordons ce sujet qu'à titre indicatif.
var myArray = new Array();
Ce code génère un tableau vide.
var myArray = new Array('valeur1', 'valeur2', …, 'valeurX');
Ce code revient à créer un tableau de cette manière :
var myArray = ['valeur1', 'valeur2', …, 'valeurX'];
var myArray = new Array(longueur_du_tableau);
Voici un cas particulier du
constructeur de l'objetArray
: il est possible de spécifier la
longueur du tableau. Cela paraît assez intéressant sur le principe, mais en réalité cela ne sert quasiment à rien vu
que le JavaScript redéfinit la taille des tableaux quand on ajoute ou supprime un item du tableau.
Ici, les tableaux ont le mérite de rendre les choses simples, ils ne
possèdent qu'une seule propriété (accessible uniquement après instanciation) que vous connaissez déjà tous
:length
! Pour rappel, cette propriété est en lecture seule et vous
indique combien d'éléments existent dans votre tableau.
Ainsi, avec ce tableau :
var myArray = [
'élément1',
'élément2',
'élément3',
'élément4'
];
La
propriétélength
renverra 4.
Plusieurs méthodes ont déjà été abordées au cours du chapitre de la première partie consacré aux tableaux. Elles sont de nouveau listées dans ce chapitre, mais de manière plus approfondie afin que celui-ci vous serve, en quelque sorte, de référence.
Aussi étrange que cela puisse paraître, le JavaScript ne permet pas l'utilisation de l'opérateur + pour concaténer plusieurs tableaux entre eux. Si on tente de s'en servir, on obtient alors en sortie une chaîne de caractères contenant tous les éléments des tableaux. Ainsi, l'opération suivante :
var myArray = ['test1', 'test2'] + ['test3', 'test4'];
alert(myArray);
donne la chaîne de caractères suivante :
test1,test2test3,test4
Pas terrible, n'est-ce pas ? Heureusement, les tableaux possèdent une
méthode nomméeconcat()
qui nous permet d'obtenir le résultat souhaité
:
var myArray = ['test1', 'test2'].concat(['test3', 'test4']);
alert(myArray);
Ce code nous retourne le tableau suivant :
['test1', 'test2', 'test3', 'test4']
Le fait de parcourir un tableau est une façon de faire très courante en programmation, que ce soit en JavaScript ou dans un autre langage. Vous savez déjà faire ça de cette manière :
var myArray = ["C'est", "un", "test"],
length = myArray.length;
for (var i = 0; i < length; i++) {
alert(
'Index : ' + i + '\n' +
'Valeur : ' + myArray[i]
);
}
Cependant, ce code est quand même contraignant, nous sommes obligés de créer deux variables, une pour l'incrémentation, et une pour stocker la longueur de notre tableau (cela évite à notre boucle d'aller chercher la longueur dans le tableau, on économise des ressources), tout ça n'est pas très pratique.
C'est là
qu'intervient une nouvelle méthode nomméeforEach()
. Cette méthode
prend pour paramètre deux arguments, le premier reçoit la fonction à exécuter pour chaque index existant et le
deuxième (qui est facultatif) reçoit un objet qui sera pointé par le mot-cléthis
dans
la fonction que vous avez spécifiée pour le premier argument.
Concentrons-nous sur la fonction passée en paramètre. Celle-ci sera exécutée pour chaque index existant (dans l'ordre croissant bien entendu) et recevra en paramètres trois arguments :
Le premier contient la valeur contenue à l'index actuel ;
Le deuxième contient l'index actuel ;
Le troisième est une référence au tableau actuellement parcouru.
Essayons donc :
var myArray = ["C'est", "un", "test"];
myArray.forEach(function(value, index, array) {
alert(
'Index : ' + index + '\n' +
'Valeur : ' + value
);
});
Vous avez sûrement constaté que nous
n'utilisons pas l'argumentarray
dans notre fonction anonyme, vous
pouvez très bien ne pas le spécifier, votre code fonctionnera sans problème !
Tout comme les chaînes de caractères, les tableaux possèdent aussi
les fonctionsindexOf()
etlastIndexOf()
.
Elles fonctionnent de la même manière, sauf qu'au lieu de ne chercher qu'une chaîne de caractères vous pouvez faire
une recherche pour n'importe quel type de valeur, que ce soit une chaîne de caractères, un nombre ou un objet. La
valeur retournée par la fonction est l'index du tableau dans lequel se trouve votre élément recherché, en cas
d'échec la fonction vous retourne toujours la valeur -1.
Prenons un exemple :
var element2 = ['test'],
myArray = ['test', element2];
alert(myArray.indexOf(element2)); // Affiche : 1
Dans ce code, c'est bien le
tableau['test']
qui a été trouvé, et non pas la chaîne de
caractères'test'
!
Pourquoi avoir créé la
variableelement2
?
Ah, en fait il y a une logique bien simple à cela :
alert(['test'] == ['test']); // Affiche : « false »
Les deux tableaux sont de même valeur
mais sont pourtant reconnus comme étant deux tableaux différents, tout simplement parce que ce ne sont pas les mêmes
instanciations de tableaux ! Lorsque vous écrivez une première
fois['test']
, vous faites une première instanciation de tableau, donc
la deuxième fois que vous écrirez cela vous ferez une deuxième instanciation.
La solution pour être sûr de comparer deux mêmes instanciations est de passer la référence de votre instanciation à une variable. Ainsi, vous n'avez plus aucun problème :
var myArray = ['test'];
alert(myArray == myArray); // Affiche : « true »
Pour terminer sur nos deux fonctions, sachez qu'elles possèdent, elles aussi, un second paramètre permettant de spécifier à partir de quel index vous souhaitez faire débuter la recherche.
Deux méthodes peuvent vous servir à trier un tableau. Nous allons
commencer par la plus simple d'entre elles :reverse()
.
reverse()
Cette méthode ne prend aucun argument en paramètre et ne retourne aucune valeur, son seul rôle est d'inverser l'ordre des valeurs de votre tableau :
var myArray = [1, 2, 3, 4, 5];
myArray.reverse();
alert(myArray); // Affiche : 5,4,3,2,1
Plutôt simple, non ?
sort()
En ce qui concerne la deuxième méthode, les choses se corsent un peu.
Celle-ci se nommesort()
, par défaut cette méthode trie votre tableau
par ordre alphabétique uniquement. Mais cette méthode possède aussi un argument facultatif permettant de
spécifier l'ordre à définir, et c'est là que les choses se compliquent. Tout d'abord, prenons un exemple simple :
var myArray = [3, 1, 5, 10, 4, 2];
myArray.sort();
alert(myArray); // Affiche : 1,10,2,3,4,5
Quand nous disions que cette méthode ne triait, par défaut, que par ordre alphabétique, c'était vrai et ce dans tous les cas ! Cette méthode possède en fait un mode de fonctionnement bien particulier : elle commence par convertir toutes les données du tableau en chaînes de caractères et ce n'est qu'après ça qu'elle applique son tri alphabétique. Dans notre exemple, la logique peut vous paraître obscure, mais si nous essayons de remplacer nos chiffres par des caractères cela devrait vous paraître plus logique :
0 = a ; 1 = b ; 2 = c
Notre suite « 1, 10, 2 »
devient donc « b, ba, c » ! Ce tri vous paraît déjà plus logique avec des caractères, non ? Eh bien, pour
la méthodesort()
, cette logique s'applique même aux chiffres !
Venons-en maintenant à l'argument facultatif
desort()
: il a pour but de réaliser un tri personnalisé. Il doit
contenir une référence vers une fonction que vous avez créée, cette dernière devant posséder deux arguments qui
seront spécifiés par la méthodesort()
. La fonction devra alors dire
si les valeurs transmises en paramètres sont de même valeur, ou bien si l'une des deux est supérieure à l'autre.
Notre but ici est de faire en sorte que notre tri soit, non pas alphabétique, mais par ordre croissant (et donc que la valeur 10 se retrouve à la fin du tableau). Nous allons donc commencer par créer notre fonction anonyme que nous fournirons au moment du tri :
function(a, b) {
// Comparaison des valeurs
}
Nous avons notre fonction, mais que
faire maintenant ? Eh bien, nous allons devoir comparer les deux valeurs fournies. Avant tout, sachez que la méthodesort()
ne
convertit pas les données du tableau en chaînes de caractères lorsque vous avez défini l'argument facultatif, ce qui
fait que les valeurs que nous allons recevoir en paramètres seront bien de
typeNumber
et non pas de typeString
,
cela nous facilite déjà la tâche !
Commençons par écrire le code pour comparer les valeurs :
function(a, b) {
if (a < b) {
// La valeur de a est inférieure à celle de b
} else if (a > b) {
// La valeur de a est supérieure à celle de b
} else {
// Les deux valeurs sont égales
}
}
Bien, nous avons fait nos
comparaisons, mais que faut-il renvoyer à la méthodesort()
pour lui
indiquer qu'une valeur est inférieure, supérieure ou égale à l'autre ?
Le principe est simple :
On retourne
-1 lorsquea
est inférieur
àb
;
On retourne 1
lorsquea
est supérieur
àb
;
Et on retourne 0 quand les valeurs sont égales.
Notre fonction devient donc la suivante :
function(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}
Essayons donc le code complet maintenant :
var myArray = [3, 1, 5, 10, 4, 2];
myArray.sort(function(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
alert(myArray); // Affiche : 1,2,3,4,5,10
Et voilà ! La
méthodesort()
trie maintenant notre tableau dans l'ordre croissant !
Il se peut que vous ayez besoin un jour ou l'autre d'extraire une
partie d'un tableau : la méthodeslice()
est là pour ça. Elle prend en
paramètre deux arguments, dont le deuxième est facultatif. Le premier est l'index (inclus) à partir duquel vous
souhaitez commencer l'extraction du tableau, le deuxième est l'index (non inclus) auquel l'extraction doit se
terminer. S'il n'est pas spécifié, alors l'extraction continue jusqu'à la fin du tableau.
var myArray = [1, 2, 3, 4, 5];
alert(myArray.slice(1, 3)); // Affiche : 2,3
alert(myArray.slice(2)); // Affiche : 3,4,5
Notons aussi que le deuxième argument possède une petite particularité intéressante qui rappellera un peu le PHP aux connaisseurs :
var myArray = [1, 2, 3, 4, 5];
alert(myArray.slice(1, -1)); // Affiche : 2,3,4
Lorsque vous spécifiez un nombre négatif au deuxième argument, alors l'extraction se terminera à l'index de fin moins la valeur que vous avez spécifiée. Dans notre exemple, l'extraction se termine donc à l'index qui précède celui de la fin du tableau, donc à l'index 3.
Nous allons aborder ici l'utilisation d'une méthode assez peu
utilisée en raison de son usage assez particulier, il s'agit
desplice()
. Cette méthode reçoit deux arguments obligatoires, puis
une infinité d'arguments facultatifs. Le premier argument est l'index à partir duquel vous souhaitez effectuer vos
opérations, le deuxième est le nombre d'éléments que vous souhaitez supprimer à partir de cet index. Exemple :
var myArray = [1, 2, 3, 4, 5];
var result = myArray.splice(1, 2); // On retire 2 éléments à partir de l'index 1
alert(myArray); // Affiche : 1,4,5
alert(result); // Affiche : 2,3
À partir de ce code, vous devriez pouvoir faire deux constatations :
La
méthodesplice()
modifie directement le tableau à partir duquel
elle a été exécutée ;
Elle renvoie un tableau des éléments qui ont été supprimés.
Continuons sur notre lancée ! Les arguments qui suivent les deux premiers contiennent les éléments qui doivent être ajoutés en remplacement de ceux effacés. Vous pouvez très bien spécifier plus d'éléments à ajouter que d'éléments qui ont été supprimés, ce n'est pas un problème. Essayons donc l'ajout d'éléments :
var myArray = [1, null, 4, 5];
myArray.splice(1, 1, 2, 3);
alert(myArray); // Affiche : 1,2,3,4,5
Notez bien aussi une chose : si vous
ajoutez des éléments dans le tableau, vous pouvez mettre le deuxième argument à 0, ce qui aura pour effet d'ajouter
des éléments sans être obligé d'en supprimer d'autres. Cette
méthodesplice()
peut donc être utilisée comme une méthode d'insertion
de données.
Pour terminer sur les méthodes des tableaux, sachez que les tableaux
possèdent une méthode propre à l'objet constructeur nomméeisArray()
.
Comme son nom l'indique, elle permet de tester si la variable passée en paramètre contient un tableau. Son
utilisation est ultra-simple :
alert(Array.isArray(['test']));
Nous allons ici aborder un concept que vous avez déjà rapidement étudié dans ce cours, mais qu'il serait bon de vous remettre en tête.
Les piles et les files sont deux manières de manipuler vos tableaux. Plutôt que de les voir comme de simples listes de données, vous pouvez les imaginer comme étant, par exemple, une pile de livres où le dernier posé sera au final le premier récupéré, ou bien comme une file d'attente, où le dernier entré sera le dernier sorti. Ces deux façons de faire sont bien souvent très pratiques dans de nombreux cas, vous vous en rendrez bien vite compte.
Quatre méthodes ont été étudiées au cours des premiers chapitres de ce cours. Il est de bon ton de revenir sur leur utilisation avant d'entamer le sujet des piles et des files :
push()
: ajoute un ou plusieurs éléments à la fin du tableau (un
argument par élément ajouté) et retourne la nouvelle taille de ce dernier.
pop()
: retire et retourne le dernier élément d'un tableau.
unshift()
: ajoute un ou plusieurs éléments au début du tableau
(un argument par élément ajouté) et retourne la nouvelle taille de ce dernier.
shift()
: retire et retourne le premier élément d'un tableau.
Les
piles partent du principe que le premier élément ajouté sera le dernier retiré, comme une pile de livres ! Elles
sont utilisables de deux manières différentes : soit avec les deux méthodespush()
etpop()
,
soit avec les deux
restantesunshift()
etshift()
.
Dans le premier cas, la pile sera empilée et dépilée à la fin du tableau, dans le deuxième cas, les opérations se
feront au début du tableau.
var myArray = ['Livre 1'];
var result = myArray.push('Livre 2', 'Livre 3');
alert(myArray); // Affiche : « Livre 1,Livre 2,Livre 3 »
alert(result); // Affiche : « 3 »
result = myArray.pop();
alert(myArray); // Affiche : « Livre 1,Livre 2 »
alert(result); // Affiche : « Livre 3 »
Aucun problème pour les
méthodespush()
etpop()
?
Essayons maintenant le
coupleunshift()
/shift()
:
var myArray = ['Livre 3'];
var result = myArray.unshift('Livre 1', 'Livre 2');
alert(myArray); // Affiche : « Livre 1,Livre 2,Livre 3 »
alert(result); // Affiche : « 3 »
result = myArray.shift();
alert(myArray); // Affiche : « Livre 2,Livre 3 »
alert(result); // Affiche : « Livre 1 »
Voilà pour les piles !
Les
files partent d'un autre principe tout aussi simple : le premier élément ajouté est le premier sorti, comme une file
d'attente. Elles sont, elles aussi, utilisables de deux manières différentes : soit avec le
couplepush()
/shift()
,
soit avec le coupleunshift()
/pop()
.
var myArray = ['Fanboy 1', 'Fanboy 2'];
var result = myArray.push('Fanboy 3', 'Fanboy 4');
alert(myArray); // Affiche : « Fanboy 1,Fanboy 2,Fanboy 3,Fanboy 4 »
alert(result); // Affiche : « 4 »
result = myArray.shift();
alert(myArray); // Affiche : « Fanboy 2,Fanboy 3,Fanboy 4 »
alert(result); // Affiche : « Fanboy 1 »
Le
coupleunshift()
/pop()
est
tout aussi simple d'utilisation :
var myArray = ['Fanboy 3', 'Fanboy 4'];
var result = myArray.unshift('Fanboy 1', 'Fanboy 2');
alert(myArray); // Affiche : « Fanboy 1,Fanboy 2,Fanboy 3,Fanboy 4 »
alert(result); // Affiche : « 4 »
result = myArray.pop();
alert(myArray); // Affiche : « Fanboy 1,Fanboy 2,Fanboy 3 »
alert(result); // Affiche : « Fanboy 4 »
Voilà pour les files !
unshift()
etshift()
Revenons maintenant sur ce petit problème de performances. Les deux
méthodesunshift()
etshift()
utilisent
chacune un algorithme qui fait qu'en retirant ou en ajoutant un élément en début de tableau, elles vont devoir
réécrire tous les index des éléments qui suivent. En gros, prenons un tableau de ce style :
0 => 'test 1' 1 => 'test 2' 2 => 'test 3'
En ajoutant un élément en début de tableau, nous cassons l'indexation :
0 => 'test supplémentaire' 0 => 'test 1' 1 => 'test 2' 2 => 'test 3'
Ce qui fait que nous devons réécrire tous les index suivants :
0 => 'test supplémentaire' 1 => 'test 1' 2 => 'test 2' 3 => 'test 3'
Si le tableau possède de nombreux éléments, cela peut parfois prendre un peu de temps. C'est ce qui fait que les piles sont généralement préférées aux files en JavaScript, car elles peuvent se passer de ces deux méthodes. Cela dit, il faut relativiser : la perte de performance n'est pas dramatique, vous pouvez très bien vous en servir pour des tableaux de petite taille (en dessous de 10 000 entrées, en gros), mais au-dessus il faudra peut-être songer à utiliser les piles ou bien à utiliser des scripts qui résolvent ce genre de problèmes.
Pour
concaténer deux tableaux, il faut utiliser la méthodeconcat()
,
car l'opérateur + ne fonctionne pas selon le comportement voulu.
La
méthodeforEach()
permet de parcourir un tableau en
s'affranchissant d'une bouclefor
.
indexOf()
etlastIndexOf()
permettent
de rechercher un élément qui peut être une chaîne de caractères, un nombre, ou même un tableau. Il faudra
toutefois faire attention lors de la comparaison de deux tableaux.
L'utilisation d'une fonction pour trier un tableau est possible et se révèle particulièrement utile pour effectuer un tri personnalisé.
Les piles et les files sont un moyen efficace pour stocker et accéder à de grandes quantités de données.