Chapitre 6 : Les tableaux

 

1 - Rappels

Nous avons introduit ce concept précédemment lorsque nous avons présenté les divers types d'objets, et en particulier, les objets dits composés. Nous avons aussi parlé de tableaux associatifs dans le précédent chapitre §5. Il est important de souligner qu'il n'y a rien à voir entre les deux ! Alors que le second constitue une façon d'accéder à des objets/propriétés via une chaîne de caractères les désignant, le premier, auquel nous nous intéresserons dans ce chapitre, sont des tableaux au sens habituel du terme dans un langage de programmation, c'est à dire, des objets qui permettent d'associer une série de valeurs à une série de nombres entiers. On dit que la série de valeurs est indicée(indexée) et chacune est accessible au moyen d'un nombre, la valeur de l'indice (index) lui correspondant.

A noter toutefois qu'à la différence d'autres langages de programmation, en JavaScript, les éléments contenus dans un même tableau peuvent être de types différents.

2 - Comment définir un tableau ?

La création d'un objet de type Array (que nous appellerons dorénavant tableau) s'opère "canoniquement" à l'aide de l'opérateur new suivi du constructeur Array. Cette méthode peut revêtir trois allures différentes : soit on définit seulement un objet tableau, sans préciser sa taille ni son contenu, soit on précise sa taille, mais pas son contenu, soit son contenu et donc, implicitement, sa taille.

Exemple :
var MonTableau1 = new Array();
var MonTableau2 = new Array(15);
var MonTableau3 = new Array(1,"Salut",3.14,void 0);

A ce point il importe de préciser quatre choses :

  • Tout indice de tableau débute en 0 (comme en C, C++, Java, etc.) ;
  • la taille d'un tableau n'est pas figée par sa définition ou son initialisation. Elle est dynamique. Le script qui suit vous en donne la preuve !!!
  • A chaque instant, la taille d'un tableau peut être connue en invoquant la propriété length de l'objet correspondant à ce tableau. (Nous verrons, à la fin de ce chapitre, un exercice mettant en jeu la possibilité d'accéder à cette propriété non seulement en lecture, mais aussi en écriture).
  • L'accès à un élément d'un tableau Tab s'opère en faisant suivre l'identificateur représentant la référence vers ce tableau (ici Tab) d'une paire de crochets (ouvrant et fermant), l'opérateur [ ], contenant une expression arithmétique s'évaluant par un entier positif ou nul et représentant la valeur de l'indice.
<script language="JavaScript">
  var T = new Array(3);
  var S ="";
  for (var i = 0; i < T.length; i++){
    T[i] = i;
  }
  T[5] = "Pourtant, j'y suis";
  for (var i = 0; i < T.length; i++){
    S += "En " + i + " on trouve " + T[i] + "\n";
  }
  alert(S);
</script>              

Par ailleurs, on peut à la fois définir et initialiser un tableau par sa forme littérale en précisant les valeurs successives entre crochets.

Exemple :
var MonTableau1 = [1,"Salut",3.14,null];
var MonTableau2 = [['essai',3],{h:3,v:12},2.7183];
var MonTableau3 = [function suc(x){return x+1},3];

La deuxième ligne de l'exemple ci-dessus montre que l'on peut avoir des tableaux multidimensionnés ou plus exactement des tableaux de tableaux. Pour accéder à un élément de tableau de niveau inférieur, on aura recours à autant d'opérateurs [ ] que de niveaux à traverser. Ainsi, dans l'exemple ci-dessus, l'écriture MonTableau2[1][1] aura pour valeur 'essai', tandis que MonTableau2[1][2] aura pour valeur 3.

3 - Les méthodes de la classe Array

La classe Array comporte un certain nombre de méthodes dont plusieurs s'inspirent du langage Perl. Elles permettent de manipuler les tableaux en les transposant en chaînes de caractères, de les inverser, de les trier, d'en extraire des sous-tableaux, de les gérer en tant que pile ou file, etc.

La méthode join()

Cette méthode s'applique à un tableau et a pour fonction de le transformer en une chaîne de caractère dans laquelle les éléments sont séparés par le caractère ",". La méthode join peut recevoir un caractère optionnel spécifiant la chaîne de caractères (éventuellement réduite à un seul caractère) qui servira à séparer les éléments. En conséquence, quel que soit le tableau Tab, Tab.join() est équivalent à Tab.join(",").
Il convient de noter (nous la verrons dans le prochain chapitre), la méthode join() a une méthode inverse, split() qui s'applique donc à un objets de type chaîne, pour transformer celui-ci en éléments d'un tableau sur la base d'un séparateur fourni en paramètre.

Nous allons imager ce duo par un exemple dans lequel à partir d'une chaîne de caractères, puis d'un caractère (ou d'une suite de caractères) auquel sera attribué le rôle de séparateur. fournira alors les éléments du tableau ainsi constitué. Sur la base d'une nouvelle chaîne de séparation, la chaîne des éléments du tableau ainsi séparés sera alors affichée;


La méthode concat()

Cette méthode réclame en argument le ou les éléments qui seront rajoutés en fin de du tableau référencé. L'absence d'argument ne provoque pas d'erreur, mais présente un intérêt limité ;-) Elle retourne comme résultat un tableau comportant en tête les éléments du tableau source et se terminant par les éléments rajoutés. Dans le cas ou l'un des éléments est un tableau, ce sont ses éléments qui sont rajoutés dans l'ordre des indices croissants. Ce traitement n'est toutefois pas récursif et si l'un des éléments rajoutés est un tableau de tableau(x) l'aplatissement n'interviendra qu'au premier niveau. Voici quelques exemples :

Comportement de concat()...

Résultat
[3,"essai",pi=3.14].concat("ajout",.159)
[3,"essai",pi=3.14].concat([1,6],true)
[3,"essai",pi=3.14].concat([1,[6,true]])
[3,"essai"].concat(false,[[4,[6,2]],31])

La méthode reverse()

Comme son nom l'indique cette méthode tout simplement inverse l'ordre des éléments du tableau référencé. Le traitement s'opère dans le tableau lui-même et ne nécessite donc pas une affectation comme c'était le cas pour concat() ou comme on le verra pour slice().


La méthode sort()

La méthode sort() agit elle aussi sur le tableau référencé afin de le trier. Par défaut, le tri s'opère par ordre alphabétique après transformation de tous les éléments qui le nécessitent en chaîne de caractères.
Par exemple, [3,"essai",true,25,["prénom","nom"],false,"in"].sort()a pour résultat : [25,3,["prénom","nom"],"essai",false,"in",true].

ATTENTION : On notera que l'ordre alphabétique n'intervient qu'au niveau le plus haut, celui du tableau effectivement trié. Le tableau enchassé n'est donc pas lui-même trié. En fait, l'ensemble formé par ce tableau enchassé est pris tel quel comme une chaîne de caractères et classé en conséquence.

Toutefois, pour avoir accès à des traitement plus subtils, cette méthode peut recevoir un argument précisant le critère de tri. Cet argument n'est autre qu'une fonction ayant elle même deux arguments réputés être deux éléments quelconques du tableau. La fonction va retourner une résultat négatif si le premier argument doit trouver place avant le second et un résultat positif dans le cas contraire. Dans le cas où les deux éléments sont équivalents, la fonction devra rendre la valeur 0.

Soit un tableau de nombres, TabN=[9,12,77,31,14,54,111]
et un tableau de chaînes de caractères, TabC=["Pascal","java","C++","fortran","COBOL","algol"]. Examinons le tri utilisant diverses fonctions...

Comportement de sort()...

Résultat
TabN.sort()
TabN.sort(function(x,y){return x-y})
TabN.sort(function(x,y){return x%2-y%2})
TabC.sort()

TabC.sort(function(x,y)      {return(x.toLowerCase()<=y.toLowerCase()?—1:1)})

 


La méthode slice()

Cette méthode est utilisée pour extraire un sous tableau du tableau référencé. Elle reçoit deux arguments et le sous tableau extrait contient les éléments du tableau source depuis l'indice désigné par le premier argument jusqu'à l'indice désigné par le second argument non compris. Dans le cas où un seul argument est spécifié, le sous tableau contient tous les éléments depuis l'indice ainsi désigné jusqu'à la fin du tableau. Enfin, si un des arguments (ou les deux) sont négatifs, l'indice désigné est relatif à la fin. Par exemple -1 désigne le dernier élément, -2, l'avant dernier, etc.
Reprenons, par exemple, le tableau de nombres précédent, TabN=[9,12,77,31,14,54,111].

Comportement de slice()...

Résultat
TabN.slice(2,5)
TabN.slice(4)
TabN.slice(2,-3)
TabN.slice(-5,5)
TabN.slice(-6,-2)

Les utilisateurs d'Internet Explorer vont s'apercevoir, dans les deux derniers exemples, que le comportement de la méthode ne correspond pas à ce qui est décrit précédemment. En effet, ce navigateur gère mal le premier paramètre lorsqu'il est négatif. L'utilisation de cette méthode doit donc prendre cela en compte.


La méthode splice()

Comme pour reverse() et sort(), cette méthode agit directement sur le tableau référencé(*). Elle a pour fonction d'insérer et/ou retirer des éléments du tableau. Le premier argument désigne l'indice dans le tableau de l'élément de départ à partir duquel la méthode va opérer (Comme pour slice() on peut ici utiliser des indices relatifs à la fin). Le second argument indique le nombre d'élément qui vont être retirés à partir de l'indice désigné précédemment. En l'absence de cet argument, c'est la fin du tableau qui est supprimée. Les arguments suivants sont en fait les éléments qui doivent être insérés dans le tableau à partir de la position indiquée par le premier argument. La méthode délivre une valeur en retour : le tableau constitué des éléments supprimés (éventuellement vide).

Voyons quelques exemples d'utilisation de cette méthode sur le tableau de chaînes de caractères TabC=["Pascal","java","C++","fortran","COBOL","algol"].

Cliquez de haut en bas afin de voir les transformations successives du tableau TabC.

Comportement de splice()...

Résultat
TabC.splice(2,1)
TabC.splice(4)
TabC.splice(1,1,"PL1","SmallTalk")
TabC.splice(3,0,["a",2],true)

(*) Cette méthode apparue sous Netscape 4 n'est supportée par Internet explorer que pour ses versions les plus récentes (>5.0x). A l'inverse des méthodes précédentes, les résultats affichés ne sont pas issus de véritables calculs mais sont des chaînes de caractères. Il faut bien que les "Exploreurs" voient ce qu'ils ratent !....

Les quatre méthodes qui vont suivre permettent une utilisation de l'objet tableau pour stoker et récupérer des valeurs, non pas par une accès aléatoire via un indice, mais en gérant le tableau sous forme d'une pile. La structure de pile est bien connue des informaticiens. Il s'agit comme son nom l'indique d'un empilement de valeurs, chaque valeur empilée venant recouvrir la précédente en écriture et seule la dernière empilée étant accessible en lecture. Il convient de préciser que l'ensemble de ces quatre méthodes n'est pas supporté par Internet explorer, seul Netscape en autorisant l'utilisation.

Les méthodes shift() & unshift()

Ces deux méthodes permettent respectivement d'empiler et de dépiler des valeurs quelconques dans un tableau en utilisant systématiquement le début du tableau pour insérer ou retirer des éléments. Cela impose donc obligatoirement une translation des éléments du tableau, soit pour laisser la place en indice 0 pour une valeur empilée, soit pour récupérer la place libérée en indice 0 par une valeur dépilée. Cela explique donc le nom de ces méthodes.

Alors que la méthode unshift() réclame des arguments (les valeurs empilées dans l'ordre de leur empilement), la méthode shift() n'a elle aucun argument puisque par définition, c'est toujours l'élément d'indice 0 qu'elle prélève. A noter que bien évidemment c'est le tableau référencé qui est lui-même affecté par l'utilisation de ces méthodes qui, par ailleurs, retournent une valeur : pour unshift() la valeur de retour indique la taille de la pile ; pour shift(), elle correspond à l'élément prélevé en tête de pile.

Soit un tableau de nombres Tab=[], voyons comment il se transforme par l'action de ces méthodes. Là encore, pour respecter la chronologie, cliquez de haut en bas.

Comportement de shift()/unshift()...

Résultat
V=Tab.unshift(22,9)
V=Tab.shift()
V=Tab.unshift(V%3,[V,V+1])
V=Tab.shift()

Les méthodes push() & pop()

Alors que les deux méthodes précédentes interviennent sur le début du tableau, push() insère une valeur en fin de tableau, de même que pop() prélève en fin de tableau. On évite ainsi le problème de translation rencontré précédemment, par contre, l'indice concerné est dynamique (la propriété length sera fort utile). A ce sujet, même si Internet explorer ne dispose pas de ces méthodes, il sera aisé de les définir. Essayez, par exemple, de réécrire la méthode pop() avant de regarder une proposition de solution.

A présent, prototypez la classe Array avec une méthode push().


Chapitre 5 : Les objetsSommaire Chapitre 7 : Les chaïnes de caractères