Image

Dynamisez vos sites web avec JavaScript !
Cours avancé de JavaScript co-écrit avec Johann Pardanaud et publié sur feu le Site du Zéro ainsi qu'en livre chez Eyrolles

Attention, ce cours est ancien (ECMAScript 5) et n'est plus au fait des dernières innovations JavaScript, mais reste une bonne base pour apprendre le language.

Les données numériques

Après l'étude des chaînes de caractères et des regex, il est temps de passer aux données numériques !
La gestion des données numériques en JavaScript est assez limitée mais elle existe quand même et se fait essentiellement par le biais des objetsNumberetMath. Le premier est assez inintéressant mais il est bon de savoir à quoi il sert et ce qu'il permet de faire ; le deuxième est une véritable boîte à outils qui vous servira probablement un jour ou l'autre.

L'objet Number

L'objetNumberest à la base de tout nombre et pourtant on ne s'en sert quasiment jamais de manière explicite, car on lui préfère (comme pour la plupart des objets) l'utilisation de son type primitif. Cet objet possède pourtant des fonctions intéressantes comme, par exemple, celle permettant de faire des conversions depuis une chaîne de caractères jusqu'à un nombre en instanciant un nouvel objetNumber:

var myNumber = new Number('3'); // La chaîne de caractères « 3 » est convertie en un nombre de valeur 3

Cependant, cette conversion est imprécise dans le sens où on ne sait pas si on obtiendra un nombre entier ou flottant en retour. On lui préfère donc les fonctionsparseInt()etparseFloat()qui permettent d'être sûr de ce que l'on obtiendra. De plus,parseInt()utilise un second argument permettant de spécifier la base (2 pour le système binaire, 10 pour le système décimal, etc.) du nombre écrit dans la chaîne de caractères, ce qui permet de lever tout soupçon sur le résultat obtenu.

Cet objet possède des propriétés accessibles directement sans aucune instanciation (on appelle cela des propriétés propres à l'objet constructeur). Elles sont au nombre de cinq, et sont données ici à titre informatif, car leur usage est peu courant :

  • NaN: vous connaissez déjà cette propriété qui signifie Not A Number et qui permet, généralement, d'identifier l'échec d'une conversion de chaîne de caractères en un nombre. À noter que cette propriété est aussi disponible dans l'espace global. Passer par l'objetNumberpour y accéder n'a donc que peu d'intérêt, surtout qu'il est bien rare d'utiliser cette propriété, car on lui préfère la fonctionisNaN(), plus fiable.

  • MAX_VALUE: cette propriété représente le nombre maximum pouvant être stocké dans une variable en JavaScript. Cette constante peut changer selon la version du JavaScript utilisée.

  • MIN_VALUE: identique à la constanteMAX_VALUEsauf que là il s'agit de la valeur minimale.

  • POSITIVE_INFINITY: il s'agit ici d'une constante représentant l'infini positif. Vous pouvez l'obtenir en résultat d'un calcul si vous divisez une valeur positive par 0. Cependant, son utilisation est rare, car on lui préfère la fonctionisFinite(), plus fiable.

  • NEGATIVE_INFINITY: identique àPOSITIVE_INFINITYsauf que là il s'agit de l'infini négatif. Vous pouvez obtenir cette constante en résultat d'un calcul si vous divisez une valeur négative par 0.

Passons donc aux essais :

var max = Number.MAX_VALUE, // Comme vous pouvez le constater, nous n'instancions pas d'objet, comme pour un accès au « prototype »
inf = Number.POSITIVE_INFINITY;
if (max < inf) {
alert("La valeur maximum est inférieure à l'infini ! Surprenant, n'est-ce pas ?");
}

Essayer le code

Du côté des méthodes, l'objetNumbern'est pas bien plus intéressant, car toutes les méthodes qu'il possède sont déjà supportées par l'objetMath. Nous allons donc faire l'impasse dessus.

L'objet Math

Après une première sous-partie assez peu intéressante, nous passons enfin à l'objetMathqui va réellement nous servir ! Tout d'abord, deux petites choses :

  • La liste des propriétés et méthodes ne sera pas exhaustive, consultez la documentation si vous souhaitez tout connaître ;

  • Toutes les propriétés et méthodes de cet objet sont accessibles directement sans aucune instanciation, on appelle cela des méthodes et des propriétés statiques. Considérez donc cet objet plutôt comme un namespace. ;)

Les propriétés

Les propriétés de l'objetMathsont des constantes qui définissent certaines valeurs mathématiques comme le nombre pi (π) ou le nombre d'Euler (e). Nous ne parlons que de ces deux constantes car les autres ne sont pas souvent utilisées en JavaScript. Pour les utiliser, rien de bien compliqué :

alert(Math.PI); // Affiche la valeur du nombre pi
alert(Math.E); // Affiche la valeur du nombre d'Euler

Voilà tout, les propriétés de l'objetMathne sont pas bien dures à utiliser donc il n'y a pas grand-chose à vous apprendre dessus. En revanche, les méthodes sont nettement plus intéressantes !

Les méthodes

L'objetMathcomporte de nombreuses méthodes permettant de faire divers calculs un peu plus évolués qu'une simple division. Il existe des méthodes pour le calcul des cosinus et sinus, des méthodes d'arrondi et de troncature, etc. Elles sont assez nombreuses pour faire bon nombre d'applications pratiques.

Arrondir et tronquer

Vous aurez souvent besoin d'arrondir vos nombres en JavaScript, notamment si vous faites des animations. Il est par exemple impossible de dire à un élément HTML qu'il fait 23,33 pixels de largeur, il faut un nombre entier. C'est pourquoi nous allons aborder les méthodesfloor(),ceil()etround().

La méthodefloor()retourne le plus grand entier inférieur ou égal à la valeur que vous avez passée en paramètre :

Math.floor(33.15); // Retourne : 33
Math.floor(33.95); // Retourne : 33
Math.floor(34); // Retourne : 34

Concernant la méthodeceil(), celle-ci retourne le plus petit entier supérieur ou égal à la valeur que vous avez passée en paramètre :

Math.ceil(33.15); // Retourne : 34
Math.ceil(33.95); // Retourne : 34
Math.ceil(34); // Retourne : 34

Et pour finir, la méthoderound()qui fait un arrondi tout bête :

Math.round(33.15); // Retourne : 33
Math.round(33.95); // Retourne : 34
Math.round(34); // Retourne : 34
Calculs de puissance et de racine carrée

Bien que le calcul d'une puissance puisse paraître bien simple à coder, il existe une méthode permettant d'aller plus rapidement, celle-ci se nommepow()et s'utilise de cette manière :

Math.pow(3, 2); // Le premier paramètre est la base, le deuxième est l'exposant
// Ce calcul donne donc : 3 * 3 = 9

Concernant le calcul de la racine carrée d'un nombre, il existe aussi une méthode prévue pour cela, elle se nommesqrt()(abréviation de square root) :

Math.sqrt(9); // Retourne : 3
Les cosinus et sinus

Lorsqu'on souhaite faire des calculs en rapport avec les angles, on a souvent recours aux fonctions cosinus et sinus. L'objetMathpossède des méthodes qui remplissent exactement le même rôle :cos()etsin()(il existe bien entendu les méthodesacos()etasin()). Leur utilisation est, encore une fois, très simple :

Math.cos(Math.PI); // Retourne : -1
Math.sin(Math.PI); // Retourne : environ 0

Les résultats obtenus sont exprimés en radians.

Retrouver les valeurs maximum ou minimum

Voici deux méthodes qui peuvent se révéler bien utiles :max()etmin(). Elles permettent respectivement de retrouver les valeurs maximum et minimum dans une liste de nombres, qu'importe si les nombres sont dans un ordre croissant, décroissant ou aléatoire. Ces deux méthodes prennent autant de paramètres que de nombres à comparer :

Math.max(42, 4, 38, 1337, 105); // Retourne : 1337
Math.min(42, 4, 38, 1337, 105); // Retourne : 4
Choisir un nombre aléatoire

Il est toujours intéressant de savoir comment choisir un nombre aléatoire pour chaque langage que l'on utilise, cela finit toujours par servir un jour où l'autre. En JavaScript, la méthode qui s'occupe de ça est nomméerandom()(pour faire original). Cette fonction est utile mais n'est malheureusement pas très pratique à utiliser comparativement à celle présente, par exemple, en PHP.

En PHP, il est possible de définir entre quels nombres doit être choisi le nombre aléatoire. En JavaScript, un nombre décimal aléatoire est choisi entre 0 (inclus) et 1 (exclu), ce qui nous oblige à faire de petits calculs par la suite pour obtenir un nombre entre une valeur minimum et maximum.

Venons-en à l'exemple :

alert(Math.random()); // Retourne un nombre compris entre 0 et 1

Essayer le code

Là, notre script est un peu limité du coup, la solution est donc de créer notre propre fonction qui va gérer les nombres minimum (inclus) et maximum (exclu) :

function rand(min, max, integer) {
if (!integer) {
return Math.random() * (max - min) + min;
} else {
return Math.floor(Math.random() * (max - min + 1) + min);
}
}

Et voilà une fonction prête à être utilisée ! Le troisième paramètre sert à définir si l'on souhaite obtenir un nombre entier ou non.

Essayer une adaptation de ce code

Cette fonction est assez simple en terme de réflexion : on prend le nombre minimum que l'on soustrait au maximum, on obtient alors l'intervalle de valeur qui n'a plus qu'à être multiplié au nombre aléatoire (qui est compris entre 0 et 1), le résultat obtenu sera alors compris entre 0 et la valeur de l'intervalle, il ne reste alors plus qu'à lui ajouter le nombre minimum pour obtenir une valeur comprise entre notre minimum et notre maximum !

Les inclassables

Bien que les objetsNumberetMathimplémentent l'essentiel des méthodes de gestion des données numériques qui existent en JavaScript, certaines fonctions globales permettent de faire quelques conversions et contrôles de données un peu plus poussés.

Les fonctions de conversion

Si vous avez lu tous les chapitres précédents (ce que vous devriez avoir fait), vous avez normalement déjà vu ces deux fonctions, mais nous allons revoir leur utilisation dans le doute.

Ces deux fonctions se nommentparseInt()etparseFloat(), elles permettent de convertir une chaîne de caractères en un nombre. La première possède deux arguments tandis que la seconde en possède un seul :

  • Le premier argument est obligatoire, il s'agit de la chaîne de caractère à convertir en nombre. Exemple :"303"donnera le nombre 303 en sortie.

  • Le deuxième argument est facultatif, mais il est très fortement conseillé de s'en servir avec la fonctionparseInt()(puisque, de toute manière, il n'existe pas avecparseFloat()). Il permet de spécifier la base que le nombre utilise dans la chaîne de caractères. Exemple : 10 pour spécifier le système décimal, 2 pour le système binaire.

L'importance du deuxième argument est simple à démontrer avec un exemple :

var myString = '08';
alert(parseInt(myString)); // Affiche : 0
alert(parseInt(myString, 10)); // Affiche : 8

Alors pourquoi cette différence de résultat ? La solution est simple : en l'absence d'un second argument, les fonctionsparseInt()etparseFloat()vont tenter de deviner la base utilisée — et donc le système de numération associé — par le nombre écrit dans la chaîne de caractères. Ici, la chaîne de caractères commence par un 0, ce qui est caractéristique du système octal, on obtient donc 0 en retour. Afin d'éviter d'éventuelles conversions hasardeuses, il est toujours bon de spécifier le système de numération de travail.

Les fonctions de contrôle

Vous souvenez-vous des valeursNaNetInfinity? Nous avions parlé de deux fonctions permettant de vérifier la présence de ces deux valeurs ; les voici :isNaN()qui permet de savoir si notre variable contient un nombre etisFinite()qui permet de déterminer si le nombre est fini.

isNaN()renvoietruesi la variable ne contient pas de nombre, elle s'utilise de cette manière :

var myNumber = parseInt("test"); // Notre conversion sera un échec et renverra « NaN »
alert(isNaN(myNumber)); // Affiche « true », cette variable ne contient pas de nombre

Quant àisFinite(), cette fonction renvoietruesi le nombre ne tend pas vers l'infini :

var myNumber = 1/0; // 1 divisé par 0 tend vers l'infini
alert(isFinite(myNumber)); // Affiche « false », ce nombre tend vers l'infini

Mais pourquoi utiliser ces deux fonctions ? Je n'ai qu'à vérifier si ma variable contient la valeurNaNouInfinity

Admettons que vous fassiez cela ! Essayons le cas deNaN:

var myVar = "test";
if (myVar == NaN) {
alert('Cette variable ne contient pas de nombre.');
} else {
alert('Cette variable contient un nombre.');
}

Essayer le code

Voyez-vous le problème ? Cette variable ne contient pas de nombre, mais ce code croit pourtant que c'est le cas. Cela est dû au fait que l'on ne fait que tester la présence de la valeurNaN. Or elle est présente uniquement si la tentative d'écriture d'un nombre a échoué (une conversion loupée par exemple), elle ne sera jamais présente si la variable était destinée à contenir autre chose qu'un nombre.

Un autre facteur important aussi, c'est que la valeurNaNn'est pas égale à elle-même !

alert(NaN == NaN); // Affiche : « false »

Bref, la fonctionisNaN()est utile car elle vérifie si votre variable était destinée à contenir un nombre et vérifie ensuite que ce nombre ne possède pas la valeurNaN.

ConcernantisFinite(), un nombre peut tendre soit vers l'infini positif, soit vers l'infini négatif. Une condition de ce genre ne peut donc pas fonctionner :

var myNumber = -1 / 0;
if (myNumber == Number.POSITIVE_INFINITY) {
alert("Ce nombre tend vers l'infini.");
} else {
alert("Ce nombre ne tend pas vers l'infini.");
}

Essayer le code

Ce code est faux, on ne fait que tester si notre nombre tend vers l'infini positif, alors que la fonctionisFinite()se charge de tester aussi si le nombre tend vers l'infini négatif.

En résumé
  • Un objet possède parfois des propriétés issues du constructeur. C'est le cas de l'objetNumber, avec des propriétés commeNumber.MAX_VALUEouNumber.NaN.

  • De même queNumber, l'objetMathpossède ce genre de propriétés. Utiliser π est alors simple :Math.PI.

  • Il faut privilégierparseInt()etparseFloat()pour convertir une chaîne de caractères en un nombre.

  • L'usage des propriétés de l'objetNumberlors de tests est déconseillé : il vaut mieux utiliser les fonctions globales prévues à cet effet, comme par exempleisNaN()au lieu deNaN.