Table of Contents
Valeurs, types et opérateurs
Below the surface of the machine, the program moves. Without effort, it expands and contracts. In great harmony, electrons scatter and regroup. The forms on the monitor are but ripples on the water. The essence stays invisibly below. Master Yuan-Ma, The Book of Programming
À l'intérieur du monde l'ordinateur, ne sont que données. Vous pouvez lire, modifier, créer des données — mais quoique ce soit qui ne soit données n'existe tout simplement pas. Toutes ces données sont stockées comme de longues séquences de bits et sont donc fondamentalement similaires.
Les bits sont tout type de choses à deux valeurs possibles, habituellement décrites comme des zéro et des un. À l'intérieur de l'ordinateur, cela prend la forme de charges électriques faibles ou fortes, d'un signal fort ou faible, d'une zone brillante ou non sur la surface d'un CD. Tout information distinct peut être réduite à une séquence de zéro et de un et donc représenté sous forme de bits.
Par exemple, imaginez comment vous pourriez représenter le nombre 13 en bits. Cela marche de la même manière que pour les nombres décimaux. Sauf qu'à la place d'avoir dix chiffres différents, vous n'en avez que deux, et le poid de chaque augmente d'un facteur de deux à chaque rang de droite à gauche. Voici les bits qui forment le nombre 13, avec la valeur des chiffres indiquée sous eux :
0 0 0 0 1 1 0 1 128 64 32 16 8 4 2 1
C'est donc le nombre binaire 00001101, ou 8 + 4 + 1, qui équivaut à 13.
Valeurs
Imaginez une mer de bits. Un océan. Un ordinateur moderne habituel a plus de 30 milliards de bits dans sa mémoire volatile. Le stockage non volatile tend à être bien plus grand.
Pour être capable de travailler avec de telles quantitées de données sans se perdre, vous devez les séparer en morceaux représentant des ensembles d'information. Dans un environnement JavaScript, ces morceaux sont appelé valeurs. Bien que les valeurs soient constituées de bits, elles jouent différents rôles. Il y a six types basiques de valeurs en JavaScript : numbers, strings, booleans, objects, functions, et undefine values.
Pour créer une valeur, vous devez juste invoquer (invoke) son nom. C'est pratique. Vous n'avez pas besoin d'apporter le matériel de construction ou payer pour celles-ci. Vous en appelez juste une et woosh, vous l'avez. Elles ne sont pas créés à partir de rien bien sûr. Chaque valeur doit être stockée quelque part, et si vous voulez en utiliser un nombre gigantesque en même temps, vous risquez de vous trouver à court de bits. Heureusement, ce n'est un problème que si vous en avez besoin tous en même temps. Dès que vous n'avez plus besoin, elle disparaissent, laissant derrière elles les bits utilisés pour être recyclés comme matériel de construction pour une nouvelle génération de valeurs.
Ce chapitre introduit les éléments atomiques des programmes JavaScript, c'est à dire les types de valeurs simples et les opérateurs qui peuvent agir sur de telles valeurs.
Nombres
Les valeurs du type number sont, sans surprise, des valeurs numériques. Dans un programme JavaScript, elles sont écrites comme suit :
13
Utilisez cela dans un programme, et cela permettra au motif de bits correspondant au numéro 13 de prendre place dans la mémoire de l'ordinateur.
JavaScript utilise un nombre fixe de bits, 64 pour être exacte, pour stocker chaque valeur de type nombre. Il y a énormément de combinaisons possibles avec 64, mais cela signifie quand même que leur nombre est limité. Pour N décimales, le nombre de nombres pouvant être représenté est 10N. De façon similaire, avec 64 caractères binaires, on peut représentert 264 nombres différents, ce qui représente 18 quintillion (18 avec 18 zéro derrière). C'est beaucoup.
La mémoire d'un ordinateur fut par le passé bien plus limitée, et les utilisateurs tendaient à utiliser des groupes de 8 ou 16 bits pour représenter leurs nombres.Il était facile d'accidentellement overflow (dépasser) d'aussi petits nombres — et de se retrouver avec un nombre qui n'entrait pas dans un si petit nombre de bits.Aujourd'hui, même les ordinateurs personnels ont une mémoire de grande taille, vous êtes donc libres d'utiliser des morceaux de 64 bits, ce qui signifie que vous n'avez à vous soucier de dépassement qu'en cas de nombres astonomiques.
Tous les nombre en dessous des 18 quintillions ne rentrent toutefois pas dans un nombre JavaScript. Ceux-ci stockent aussi des nombres négatif, un bit indique donc le signe du nombre. Un autre soucis est que les nombres non entiers doivent aussi être représentés. Pour cela, quelques bits sont utilisés pour stocker la position du point décimal (de la virgule). Le nombre entier maximum qu'il est possible de stocker est plutôt dans la fourchette de 9 quadrillions (15 zéro), ce qui encore plutôt grand.
Les nombres fractionnels sont écrits en utilisant un point.
9.81
Pour les nombres très grands ou très petits, vous pouvez aussi utiliser la notation scientifique en utilisant un “e” (pour “exposant”), suivi de l'exposant du nombre :
2.998e8
Ce qui correspond à 2.998 × 108 = 299,800,000.
Les calculs avec des nombres entiers plus petit que le nombre précédemment cité de 9 quintillions garantissent de toujours être précis. Malheureusement, les calculs avec des nombres fractionnels ne le sont généralement pas. Tout comme π (pi)ne peut être exprimé précisemment avec un nombre fini de caractères décimaux, de nombreux nombres perdent en précision lorsque seuls 64 bits sont utilisés pour les représenter. C'est fort fâcheux, mais cela ne cause des problèmes pratiques que dans des situations spécifiques. La chose importante est d'en être conscient et de traiter les nombres fractionnels comme des approximations et non des valeurs précises.
Arithmétique
La principale chose à faire avec des nombres est de l'arithmétique. Les opérations arithmétiques comme les additions ou les multiplications prennent deux nombres et produisent un nouveau avec ceux-ci. Voilà à quoi cela ressemble en JavaScript :
100 + 4 * 11
Les symboles + et * sont appelés des opérateurs. Le premier correspond à l'addition, le second à la multiplication. Mettre un opérateur entre deux valeurs s'appliqura à ses deux valeurs et produira une nouvelle valeur.
L'exemple signifie-t-il “ajouter 4 à 100, et multiplier le résultat par 11”, ou la multiplication est-elle faite avant l'addition ? Comme vous l'avez peut-être deviné, la multiplication arrive en premier. Mais en mathématique, vous pouvez changer cela en insérant l'addition dans des parenthèses.
(100 + 4) * 11
Pour la soustraction, il y a l'opérateur -, et la division peut être faite avec l'opérateur /.
Lorsque les opérateurs apparaissent ensemble sans parenthèses, l'ordre dans lequel ils sont appliqués est déterminé par la précédence des opérateurs. L'exemple montre que la multiplication est effectuée avant l'addition. L'opérateur / a la même précédence que *. De même pour + et -. Lorsque des opérateurs avec la même précédence, comme pour 1 - 2 + 1, ils sont appliqués de gauche à droite :(1 - 2) + 1.
These rules of precedence are not something you should worry about. When in doubt, just add parentheses. Les règles de précédence ne sont pas quelque chose dont vous devriez vous soucier.
Il existe encore un opérateur arithmétique, que vous pourriez ne pas reconnaître immédiatement. Le symbole % est utilisé pour représenter le reste d'une division euclidienne. X % Y est ce qu'il reste lorsque l'on divise X par Y. Par exemple 314 % 100 produit 14, et 144 % 12 donne 0. La précédence du modulo est la même que celle de la multiplication et de la division. Vous verrez de temps à autre cet opérateur appelé modulo, quoique techniquement le terme though technically reste soit plus précis.
Nombres spéciaux
Il existe trois valeurs spéciales en JavaScript qui sont considérées comme des nombres mais n'agissent pas comme des nombres normaux.
Les deux premiers sont Infinity et -Infinity, qui représentent les infinis positifs et négatifs. Infinity - 1 est toujours Infinity, et ainsi de suite. Ne mettez pas trop de confiance dans les calculs basés sur les infinis. Ça n'est pas mathématiquement solide, et amènera très rapidement à notre autre nombre spécial : NaN.
NaN signifie “not a number”, même si cette valeur est du type Number. Vous obtiendrez cette valeur lorsque, par exemple, vous essaierez de calculer 0 / 0 (zéro divisé by zéro), Infinity - Infinity, ou tout autre nombre ou opération numérique qui ne sort pas un résultat précis et significatif.
Strings
Le prochain type de donnée basique est string, ou chaîne de caractère en français. Les chaînes de caractères sont utilisées pour représenter du texte. Elles sont écrite en entourant leur contenu de guillements droits.
"Patch my boat with chewing gum" 'Monkeys wave goodbye'
Les guillemets droits imples et doubles peuvent être utilisés les uns comme les autres tant que le guillement de départ est le même que celui de fin.
À peu prêt tout peut être mis entre guillements droits, et JavaScript en fera une valeur string. Mais quelques caractères peuvent être plus complexes. Vous pouvez vous imaginer comme mettre des guillements droits entre guillements droits peut être compliqué. Les caractères Newlines (ceux que vous obtenez lorsque vous appuyez sur Entrée) ne peuvent pas non plus être mis entre guillements droits. La chaîne de caractère doit rester sur une unique ligne.
Pour rendre possible d'inclure de tels caractères, la notation suivante est utilisée : Lorsqu'un backslash (\) est trouvée dans le texte, il indique que le caractère qui le suit à une signification spéciale. On appelle cela un caractère d'escaping. Une guillemet droit précédé par un backslah ne mettra pas fin à la chaîne de caractère mais sera part de celui-ci. Lorsque le caractère n est précédé d'un backslash, il est interprété comme un caractère newline. De ma même manière, le caractère t précédé d'un backslash représente un caractère tab. Prenez la chaîne de caractère suivant :
"This is the first line\nAnd this is the second"
Le texte contenu est le suivant :
This is the first line And this is the second
Il y a, bien sûr, des situation où l'on souhaite s'implement avoir un backslash dans une chaîne de caractère, et non un code spécial. Si deux backslash se suivent, ils fusionnent, et il n'en reste qu'un dans la chaîne de caractère. C'est ainsi que la chaîne de caractère “A newline character is written like “\n”.” peut être exprimée :
"A newline character is written like \"\\n\"."
Les chaînes de caractère ne peuvent être divisées, multipliées ou soustraites, mais l'opérateur + peut être utilisé sur eux. Il n'ajoute pas concatène—il colle deux chaînes de caractères l'une à l'autre. La ligne suivante produit la chaîne “concatenate”:
"con" + "cat" + "e" + "nate"
Il y a bien d'autres manières de manipuler des chapines de caractère, nous en discuterons lorsque nous en viendrons aux méthodes dans le chapitre 4.
Opérateurs unaires
Tous les opérateurs ne sont pas des symboles. Certains sont écrit comme des mots. Un exemple est l'opérateurtypeof operator, qui produit une chaîne de caractère nommant le type de la valeur que vous lui donnez.
console.log(typeof 4.5) // → number console.log(typeof "x") // → string
Nous utiliserons console.log dans le code d'exemple pour indiquer que nous souhaitons voir le résultat de l'évaluation de quelque chose. Lorsque vous exécutez ce type de code, la valeur produite devrait être affichée à l'écran, quoique la manière d'apparaître dépendra de l'environnement JavaScript au travers duquel vous l'utiliserez.
Les autres opérateurs que nous avons vu prennent deux valeurs, mais typeof n'en prend qu'une. Les opérateurs qui prennent deux valeurs sont appelé opérateurs binaires, tandis que ceux qui n'en prennent qu'un sont appelés opérateurs unaires. L'opérateur - peut être utilisé aussi bien comme opérateur binaire qu'unaire.
console.log(- (10 - 2)) // → -8
Valeurs booléennes
De temps à autre, vous aurez besoin d'une valeur qui distingue simplement deux possibilités, telles que “oui” et “non” ou “en marche” et “éteind”. Pour cela, JavaScript à un type Booléen, qui consiste en deux valeur : true et false (vrai ou faux). Comparaisons
Voici une manière de produire des valeurs booléennes :
console.log(3 > 2) // → true console.log(3 < 2) // → false
Les signes > et < sont traditionnelement des symboles pour “plus grand que” et “plus petit que”, respectively. Ce sont des opérateurs binaires. Les appliquer aura pour résultat une valeur booléenne qui indique s'ils sont vrais dans ce cas.
Les chaînes de caractères peuvent être comparées de la même manière.
console.log("Aardvark" < "Zoroaster") // → true
La manière dont les chaînes de caractère sont ordonnées est plus ou moins alphabétique : Les lettres capitales sont toujours “moins” que les minuscules, par conséquent “Z” < “a” est vrai, et les caractères non-alphabétiques (!, -, et ainsi de suite) sont aussi inclus. La comparaison est basée sur le standard Unicode. Ce standard assigne un nombre à virtuellement tous les caractères dont vous auriez jamais besoin, incluant les caractères grecs, arabes, japonais, tamous et ainsi de suite. Avoir de telles nombres est utile pour les représenter comme une séquence de nombres.Lorsque l'on compare les chaînes de caractère, JavaScript va de gauche à droite, comparant les codes numériques des caractères un à un.
D'autres opérateurs similaires sont >= (plus grand ou égal à), ⇐ (moins que ou égale à), == (égal à), et != (non égal à).
console.log("Itchy" != "Scratchy") // → true
Il n'est qu'une valeur en JavaScript qui ne soit pas égal à elle-même, il s'agit de NaN, qui signifie “not a number”.
console.log(NaN == NaN) // → false
NaN est supposé dénoter le résultat d'un calcul insensé, et comme tel, il n'est pas égal à n'importe autre calcul insensé.
Opérateurs logiques
Il y a aussi quelques opérations qui peuvent être appliquées aux valeurs booléennes elles-mêmes. JavaScript supporte trois opérateurs logiques : and, or, et not. Ils peuvent être utilisé pour “raisonner” a propos de booléens.
L'opérateur && représente l'opérateur logique and. C'est un opérateur binaire, et le résultat est vrai uniquement si les valeurs qui lui sont donné sont vraies.
console.log(true && false) // → false console.log(true && true) // → true
L'opérateur || dénote un or logique. Il produit true si l'une ou l'autre valeur est vraie.
console.log(false || true) // → true console.log(false || false) // → false
Not est écrit avec un point d'exclamation (!). C'est une opérateur unaire qui inverse la valeur qui lui est donnée — !true produit false et !false donne true.
Lorsque l'on mélange les opérateurs booléens avec de l'arithmétique et d'autres opérateurs, il n'est pas toujours évident de savoir quand les parenthèses sont nécéssaires. En pratique, vous pouvez habituellement vous en sortir en sachant que des opérateurs que nous avons vu jusqu'ici, || a la plus faible précédence, suivi de &&, et enfin des autres opérateurs de comparaison (>, ==, et ainsi de suite), puis le reste. Cet ordre a été choisi de telle manière que, dans une expression typique comme celle qui suit, aussi peut de parenthèses que possible sont nécéssaires :
1 + 1 == 2 && 10 * 10 > 50
Les dernière opérateur logique dont je vais discuter est un opérateur non pas unaire, non pas binaire, mais ternaire, opérant sur trois valeurs. Il est écrit avec un point d'interrogation et un point-virgule, comme ceci :
console.log(true ? 1 : 2); // → 1 console.log(false ? 1 : 2); // → 2
Celui-ci est appelé l'opérateur conditionel (ou parfois juste l'opérateur ternaire étant donné qu'il est le seul opérateur de ce type dans le langage). The value on the left of the question mark “picks” which of the other two values will come out. Lorsque c'est crai, la valeur du milieu est choisie, et lorsque c'est faux, la valeur à droite est choisie.
Valeurs indéfinies
Il y a deux valeurs spéciales, écrites null et undefined, qui sont utilisées pour dénoter l'absence d'information significative. Ce sont elles-même des valeurs, mais elle ne contiennent aucune information.
De nombreuses opérations dans le langage ne produisent pas de valeur significative (vous en verrez plus tard) et renvoient undefined simplement parce qu'elle ont à renvoyer some value.
La différence de sens entre undefined et null est un accident dans la conception de Javascript, et ça n'a la plupart du temps pas d'incidence. Dans le cas ou vous auriez effectivement a vous intéresser à ces valeurs, je vous recommande de les traiter comme interchangeables (nous allons en voir plus dans un moment).
Conversion automatique de types
Dans l'introduction, j'ai mentionné que JavaScript acceptait a peu près n'importe quel code, even du code faisant des choses bizarres. Cela est bien démontré par ces expressions :
console.log(8 * null) // → 0 console.log("5" - 1) // → 4 console.log("5" + 1) // → 51 console.log("five" * 2) // → NaN console.log(false == 0) // → true
Lorsqu'un opérateur est appliqué au “mauvais” type de valeur, JavaScript va silencieusement convertir la valeur dans le type dont il a besoin, en utilisant un ensemble de règles qui ne sont pas nécéssairement celles que vous souhaitiez ou attendiez. On appelle cela type coercion. Le null de la première expression devient 0, et le “5” de la seconde expression devient 5 (d'une chaîne de caractères devient un nombre). À nouveau dans la troisième expression, + tente une concaténation de chaînes de caractères avant une addition numérique, le 1 est converti en “1” (d'un nombre une chaîne de caractères).
Lorsque quelque chose qui ne se converti pas en un nombre d'une manière évidente (comme “five”ou undefined) est converti en un nombre, la valeur prduite est NaN. Davantage d'opération arithmétiques sur NaN continuerons de produire NaN, alors si vous vous retrouver avec un de ceux-là à un endroit inattendu, chercher des conversions de type accidentelles.
Lors de comparaison de valeurs en utilisant ==, le résultat est facile à prédire : vous devriez avoir true lorsque les deux valeurs sont les même, à l'exception du cas de NaN. Mais lorsque le type diffère, JavaScript utilise un ensemble de règles compliquées et déroutantes pour déterminer que faire. Dans la majorité des cas, il essaie de convertir le type d'une des valeurs en le type de l'autre valeur. Cependant, si null ou undefined apparaissent d'un côté ou de l'autre d'un opérateur, il ne renvoie true que si les deux valeurs sont null ou undefined.
console.log(null == undefined); // → true console.log(null == 0); // → false
Ce dernier comportement est parfois utile. Lorsque vous souhaitez tester si une valeur à une valeur réelle plutôt que null ou undefined, vous pouvez simplement la comparer avec null avec l'opérateur == (ou !.
Mais si vous souhaitez tester si quelque chose réfère à la valeur précise false? Les règles stipulent que pour la conversion des chaînes de caractères et des nombre en booléens, 0, NaN, et la chaîne de caractère vide (“”) comptent comme false, tandis que toutes les autres valeurs comptent pour true. À cause de cela, les expressions comme 0 == false et “” == false sont aussi vraies. Pour les cas tels que celui-ci, ou vous ne voulez pas la moindre conversion automatique, il existe deux autres opérateurs : === et !==. Le premier teste si une valeur est précisemment égal à l'autre, et la seconde teste si elle ne sont pas précisément égales. Donc “” === false est faux comme attendu.
Je recommande d'utiliser les comparaisons à trois caractères de manière défensive pour prévenir des conversions de type inattendues pouvant poser problème. Mais lorsque vous êtes certain que les types sont les mêmes de chaque côté, il n'y a pas de problème à utiliser les opérateurs plus courts.
Court-circuitage des opérateurs logiques
Les opérateurs logiques && et || prennent en charge les valeurs de différents types de manière particulière. Ils convertiront la valeur à leur gauche en type booléen pour décider quoi faire, mais selon l'opérateur et le résultat de cette conversion, ils retourneront soit la valeur original de gauche, soit la valeur à droite.
L'opérateur || , par exemple, retournera la valeur à sa gauche lorsqu'elle peut être convertie à true et retournera la valeur à se droite dans le cas contraire. La conversion marche comme vous l'attendriez pour une valeur booléenne et devrait faire quelque chose d'analogue pour les autres types.
console.log(null || "user") // → user console.log("Karl" || "user") // → Karl
Cette fonctionnalité permet à l'opérateur || d'être utilisé comme un moyen de définir une valeur par défaut. Si vous donnez une expression qui pourrait produire une valeur vide à gauche, la valeur à droite sera utilisé comme remplacement.
L'opérateur && fonctionne de manière similaire, mais dans l'autre sens. Lorsque la valeur à sa gauche est convertie vers false, il retourne cette valeur, et retourne la valeur de droite dans le cas contraire.
Une autre propriété important de ces deux opérateurs est que l'expression à leur droite n'est évaluée que si nécessaire. Dans le cas detrue || X, quoique X soitc— même si c'est une expression qui fait quelque chose de terrible — le résultat sera true, et X ne sera jamais évalué. La même chose pour false && X, qui est toujours false et ignorera X. On appelle cela une short-circuit evaluation.
L'opérateur conditionnel fonctionne de manière similaire. La première expression est toujours évaluée, mais la seconde ou la troisième, celle qui n'est pas sélectionnée, ne l'est pas.
Summary
Nous avons considéré quatre types de valeurs JavaScript dans ce chapite : nombres, chaînes de caractères, booléens, et valeurs indéfinies.
Les valeurs de ces types sont créés en tapant leur nom (true, null) ou valeur (13, “abc”). Vous pouvez combiner et transformer ces valeurs avec des opérateurs. Nous avons vu les opérateurs binaires pour l'arithmétique (+, -, *, /, and %), la concaténation de chaînes de caractères (+), la comparaison (==, !=, ===, !==, <, >, ⇐, >, et la logique (&&, ||), ainsi que plusieurs opérateurs unaires (- pour passer un nombre en négatif, ! pour la négation logique, et typeof pour trouver le type d'une valeur) et un opérateur ternaire (?:) pour choisir une valeur parmi deux sur la base d'une troisième valeur.
Cela vous donne suffisamment d'informations pour utiliser JavaScript comme une calculette de poche, mais pas beaucoup plus. Dans le prochain chapitre, nous commencerons à lier ensemble ces expressions dans des programmes basiques.