ÉLOQUENT JAVASCRIPT

3e Édition

Marijn Haverbeke

Traducteur

CptNome

Voici un livre qui traite du contrôle des ordinateurs. Aujourd’hui, les ordinateurs sont aussi communs que le sont les tournevis, mais ils sont hautement plus complexes, et faire de sorte qu’ils puissent exécuter ce que vous voudriez qu’ils fassent n’est pas toujours si facile.

Si la tâche que vous souhaitez que l’ordinateur exécute est très commune, une tâche bien définie, comme afficher vos courriels ou agir à titre de calculatrice, vous pouvez simplement ouvrir l’application appropriée et l’utiliser. Mais pour les tâches uniques ou tâches sans fin, il n’existe probablement pas d’application.

Commentez

- Titre : ÉLOQUENT JAVASCRIPT

- Auteur : Marijn Haverbeke

- Traducteur : CptNome

- Parution : 19 juillet 2019

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2019 Marijn Haverbeke. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. La programmation

- I-B. Pourquoi les langages sont importants

- I-C. Qu’est-ce que JavaScript

- I-D. Quoi faire avec le code ?

- I-E. Vue d’ensemble de ce livre

- I-F. Conventions typographiques

- II. Valeurs, Types et Opérateurs

- II-A. Valeurs

- II-B. Nombres

- II-B-1. Arithmétique

- II-B-2. Nombres spéciaux

- II-C. Chaînes

- II-D. Opérateurs unaires

- II-E. Valeurs booléennes

- II-E-1. Comparaison

- II-E-2. Opérateurs logiques

- II-F. Valeurs vides

- II-G. Conversion de type automatique

- II-G-1. Court-circuiter les opérateurs logiques

- II-H. Résumé

I - Introduction

« Nous pensons que nous créons le système pour nos propres usages. Nous croyons que nous le construisons à notre image… Mais l’ordinateur n’est pas vraiment comme nous. Il s’agit d’une projection d’une très petite partie de nous-même : cette partie dévouée à la logique, l’ordre, les règles et la clarté. »

- Ellen Ullman, Close to the Machine : Technophilia and its Discontents

Micro-ordinateur et tournevis

C’est ici que la programmation peut entrer en jeu. Programmer est l’acte de construire un programme – un ensemble précis d’instructions indiquant à un ordinateur quoi faire. Parce que les ordinateurs sont des bêtes stupides et pédantes, la programmation est fondamentalement fastidieuse et frustrante.

Heureusement, si vous arrivez à faire abstraction de ce désagrément et peut-être même apprécier la rigueur de penser dans les termes que ces machines stupides peuvent comprendre, la programmation peut devenir gratifiante. Cela vous permet de réaliser en quelques secondes des tâches impossibles à réaliser à la main. C’est un moyen pour que votre ordinateur réalise des choses qu’il ne pouvait faire auparavant. Et tout cela procure un merveilleux exercice de pensée abstraite.

La plupart des programmes sont réalisés avec des langages de programmation. Un langage de programmation est un langage artificiel inventé pour fournir des instructions aux ordinateurs. Il est intéressant de remarquer que la manière la plus efficace que nous ayons trouvée pour communiquer avec l’ordinateur soit aussi similaire à la façon dont on communique entre nous. Comme les langages humains, les langages informatiques permettent à des mots et des phrases d’être combinés de façon nouvelle, rendant possible l’expression de tout nouveaux concepts.

Au début, les interfaces basées sur le texte telles que les invites de commandes BASIC et DOS des années 80 et 90 étaient le moyen principal d’interagir avec les ordinateurs. Elles ont largement été remplacées par des interfaces graphiques, qui sont plus faciles d’approche, mais qui offrent moins de liberté. Les langages de programmation sont toujours présents si vous savez où regarder. Un de ces langages, JavaScript, est intégré dans tous les navigateurs web modernes et de ce fait, est disponible sur la plupart des appareils.

Ce livre va tenter de vous le rendre suffisamment familier pour vous permettre de faire des choses utiles et amusantes avec ce langage.

I-A - La programmation

Parallèlement à l’enseignement du JavaScript, je vais vous initier aux principes de base de la programmation. Il s’avère que la programmation est difficile. Les règles fondamentales sont claires et simples, mais les programmes construits sur ces règles tendent à devenir assez complexes pour introduire leurs propres règles et de nouvelles complexités. D’une certaine manière, vous construisez votre propre labyrinthe et vous pourriez bien vous y perdre.

Pendant la lecture de ce livre, il y aura des moments terriblement frustrants. Si vous êtes nouveau dans la programmation, il y aura beaucoup de nouvelle matière à digérer. La plupart des éléments de cette matière seront alors combinés de manière à approfondir votre compréhension.

Libre à vous de faire les efforts nécessaires. Lorsque vous avez du mal à suivre le livre, ne partez sur aucune conclusion hâtive concernant vos propres capacités. Vous êtes capable – vous avez juste besoin de persévérer. Prenez une pause, relisez certains passages et assurez-vous de lire et de comprendre les exemples de programmes et les exercices. Apprendre est un travail difficile, mais chaque chose que vous apprendrez vous appartiendra et rendra l’apprentissage subséquent plus facile.

« Quand les actions deviennent non productives, ramassez de l’information ; quand les informations deviennent indigestes, dormez. »

- Ursula L. Le Guin, The Left Hand of Darkness

Un programme est l’ensemble de plusieurs éléments. C’est un morceau de texte rédigé par un programmeur, c’est la force dirigeante qui fait que l’ordinateur fait ce qu’il fait, ce sont les données dans la mémoire de l’ordinateur, d’ailleurs il contrôle les actions effectuées sur cette même mémoire. Les analogies qui tentent de comparer un programme à des objets familiers sont souvent incomplètes. Celle qui convient le mieux est celle d’une machine – beaucoup de parties différentes sont généralement impliquées et pour que l’ensemble se tienne, nous devons considérer les façons dont ces parties sont interconnectées et contribuent au fonctionnement de l’ensemble.

Un ordinateur est une machine physique qui agit comme l’hôte de ces machines immatérielles. Les ordinateurs en soi ne peuvent seulement effectuer que des actions simples et stupides. La raison pour laquelle ils sont si utiles est qu’ils exécutent ces actions à une vitesse incroyablement élevée. Un programme peut ingénieusement combiner une quantité gigantesque de ces actions simplissimes afin de réaliser des choses beaucoup plus complexes.

Un programme est une construction de pensées. Ça ne coûte rien à construire, ça ne pèse rien, et ça grandit rapidement au rythme de vos doigts sur le clavier.

Mais sans attention, la taille d’un programme et sa complexité vont s’étendre hors de contrôle, mystifiant même la personne qui l’a créé. Garder un programme sous contrôle est le principal problème en programmation. Quand un programme fonctionne, c’est merveilleux. L’art de la programmation est l’aptitude de contrôler la complexité. L’enjeu principal est subtil – faire simple à travers la complexité.

Certains programmeurs croient que cette complexité est mieux contrôlée en utilisant seulement de petits ensembles de techniques très bien comprises dans leurs programmes. Ils ont établi des règles strictes (« les bonnes pratiques ») prescrivant la forme qu’un programme devrait avoir et ils restent prudemment à l’intérieur de leur petite zone de confort.

Ceci n’est pas seulement ennuyant, c’est inefficace. Les nouveaux problèmes nécessitent souvent de nouvelles solutions. Le monde de la programmation est très jeune et continue de se développer rapidement, et est assez varié pour laisser largement de place à différentes approches. Il y a de nombreuses et terribles méprises à faire dans le design d’un programme, et vous devriez progresser de manière à comprendre ce que vous faites. L’instinct de savoir à quoi ressemble un bon programme s’acquiert avec la pratique, non en suivant une liste de règles.

I-B - Pourquoi les langages sont importants

Au tout début de l’informatique, il n’y avait pas de langages. Les programmes ressemblaient à ceci :

00110001 00000000 00000000

00110001 00000001 00000001

00110011 00000001 00000010

01010001 00001011 00000010

00100010 00000010 00001000

01000011 00000001 00000000

01000001 00000001 00000001

00010000 00000010 00000000

01100010 00000000 00000000

Voici un programme qui ajoute ensemble tous les nombres de 1 à 10 et imprime le résultat : 1 + 2 + … + 10 = 55. Il pourrait s’exécuter sur une simple et hypothétique machine. Pour programmer sur les premiers ordinateurs, il était nécessaire de configurer de grands ensembles de commutateurs dans la bonne position ou encore perforer des trous dans un ruban ou une carte et les insérer dans l’ordinateur. Vous pouvez probablement imaginer comment cette procédure était fastidieuse et sujette aux erreurs. Même écrire de simples programmes demandait une grande intelligence et de la discipline. Les programmes plus complexes étaient pratiquement inconcevables.

Évidemment, entrer manuellement ces mystérieux schémas de bits (des uns et des zéros) procurait au programmeur le sentiment profond d’être un puissant sorcier. Et cela devait en valoir la peine en termes de satisfaction professionnelle.

Chacune des lignes du précédent programme contient une instruction unique. On pourrait le traduire en français ainsi :

1. Écrire le nombre 0 à l’emplacement mémoire 0.

2. Écrire le nombre 1 à l’emplacement mémoire 1.

3. Écrire la valeur située à l’emplacement mémoire 1 dans l’emplacement à l’adresse 2.

4. Soustraire le nombre 11 de la valeur située à l’emplacement mémoire 2.

5. Si la valeur à l’emplacement mémoire 2 est le nombre 0, continuer avec l’instruction 9.

6. Ajouter la valeur située à l’emplacement mémoire 1 à la valeur située à l’emplacement mémoire 0.

7. Ajouter le nombre 1 à la valeur située à l’emplacement mémoire 1.

8. Continuer avec l’instruction 3.

9. Afficher la valeur située à l’emplacement mémoire 0.

Bien que cela soit déjà plus lisible que la soupe de bits, cela reste sensiblement obscur. Il est beaucoup plus aisé d’utiliser des noms à la place des nombres pour les instructions et les adresses mémoires.

1. Affecter la variable total à 0.

2. Affecter la variable compteur à 1.

3. [boucle]

4. Affecter la variable comparer à la variable compteur.

5. Soustraire 11 de la variable comparer.

6. Si comparer est égal à zéro, continuer à [fin].

7. Ajouter compteur à total.

8. Ajouter 1 à compteur.

9. Continuer à [boucle].

10. [fin]

11. Afficher total.

À ce moment, pouvez-vous comprendre comment le programme fonctionne ? Les deux premières lignes affectent leur valeur initiale à deux emplacements mémoire : total sera utilisé pour compiler le résultat du calcul, et compteur servira à faire le suivi du nombre auquel nous nous sommes rendus. Les lignes utilisant comparer sont probablement les plus étranges. Le programme veut savoir si compteur est égal à 11 pour décider s’il peut arrêter son exécution. Puisque notre machine hypothétique est plutôt primitive, elle peut seulement comparer si un nombre est zéro, puis prendre une décision en conséquence. Donc, le programme utilise l’emplacement mémoire nommé comparer pour calculer la valeur de compteur - 11 et prendre une décision basée sur cette valeur. Les deux lignes suivantes ajoutent la valeur de compteur au résultat et augmentent compteur de 1 chaque fois que le programme décide que compteur n’est pas encore égal à 11.

Voici le même programme en JavaScript :

1. let total = 0, count = 1;

2. while (count <= 10) {

3. total += count;

4. count += 1;

5. }

6. console.log(total);

7. // → 55

Cette version apporte quelques améliorations. Le plus important, il n’est plus nécessaire de spécifier la manière dont nous voulons que le programme saute en arrière et en avant. La boucle while s’en charge. Elle continue d’exécuter le bloc (entouré par les accolades) en dessous aussi longtemps que la condition fournie est respectée. Cette condition est « count <= 10 », ce qui veut dire « count est plus petit ou égal à 10 ». Nous n’avons plus besoin de créer une valeur temporaire pour la comparer à zéro, détail qui était tout simplement insignifiant. Une partie de la puissance des langages de programmation est qu’ils peuvent s’occuper des détails insignifiants pour nous.

À la fin du programme, après que la boucle while est terminée, l’instruction console.log est utilisée pour afficher le résultat.

Finalement, voici ce à quoi le programme aurait pu ressembler si nous avions eu les commandes d’instructions range et sum disponibles qui, respectivement, créent une collection de nombres à l’intérieur d’un intervalle donné et calcule la somme de la collection de nombres :

1. console.log(sum(range(1, 10))) ;

2. // → 55

La morale de cette histoire est qu’un même programme peut être rédigé d’une manière courte ou longue, de façon peu lisible ou facile à comprendre. La première version du programme était extrêmement obscure, alors que la version finale est presque un langage humain (anglais) : « log the sum of the range of numbers from 1 to 10 ». (« Afficher la somme des nombres dans l’intervalle de 1 à 10 ».) (Nous verrons dans les chapitres suivants comment définir des opérations comme sum et range.)

Un bon langage de programmation aide le programmeur en lui permettant de parler à un niveau plus élevé des actions que l’ordinateur doit accomplir. Il aide à éviter d’avoir à tenir compte des détails, il fournit des blocs d’instructions pratiques (tel que while et console.log), il permet de définir ses propres blocs d’instructions (tel que sum et range), et rend ces blocs faciles à construire.

I-C - Qu’est-ce que JavaScript

JavaScript fut introduit en 1995 comme une manière d’ajouter des programmes dans les pages web sur le navigateur Netscape. Le langage est désormais intégré dans tous les grands navigateurs web graphiques. Il rend possibles les applications web modernes – applications avec lesquelles vous interagissez directement sans devoir recharger la page à chaque action. JavaScript est utile également dans les sites web plus traditionnels en fournissant différentes formes d’interactivités et de fonctionnalités.

Il est important de noter que JavaScript n’a pratiquement rien à voir avec le langage de programmation nommé Java. Les similarités de nom furent inspirées par des considérations marketing plutôt que par bon jugement. Quand JavaScript fut introduit, le langage Java était fort et gagnait en popularité. Quelqu’un pensa qu’il serait judicieux de surfer sur ce succès. Maintenant nous sommes pris avec ce nom.

Après son adoption en dehors de Netscape, un standard fut défini pour décrire la façon dont le langage JavaScript devait fonctionner de manière à ce que les nombreux logiciels qui revendiquaient supporter JavaScript puissent parler du même langage. Il se nomme le standard ECMAScript, d’après l’organisation internationale Ecma qui fut à l’origine de la standardisation.

Certaines personnes disent des choses horribles à propos de JavaScript. Certaines de ces choses sont vraies. Quand je dus écrire quelque chose en JavaScript pour la première fois, j’en suis venu rapidement à mépriser ce langage. Il pouvait accepter pratiquement tout ce que j’écrivais, mais l’interprétait d’une manière complètement différente de ma volonté. Cela avait beaucoup à voir avec le fait que je n’avais aucune idée de ce que je faisais, bien sûr, mais il y a un véritable problème là : JavaScript est ridiculement permissif. L’idée derrière cette conception était que cela rendrait la programmation JavaScript plus facile pour les débutants. Dans les faits, cela rend plus ardu de trouver les problèmes dans vos programmes parce que le système ne vous les indique pas expressément.

Par ailleurs, cette flexibilité a aussi ses avantages. Cela laisse place à beaucoup de techniques qui sont impossibles à réaliser avec les langages plus stricts ; et comme vous pourrez le découvrir par exemple au chapitre 10, cela permet de surmonter certaines lacunes de JavaScript. Après avoir appris le langage convenablement et travaillé avec lui un certain temps, j’ai commencé à aimer JavaScript.

Il y a eu plusieurs versions de JavaScript. ECMAScript version 3 fut la plus largement supportée des versions pendant la grande ascension de JavaScript aux alentours de 2000 à 2010. À cette époque, les travaux sur l’ambitieuse version 4 étaient en cours, et planifiaient un nombre important d’améliorations et d’extensions au langage. Changer radicalement un langage vivant et largement utilisé s’est avéré politiquement difficile et les travaux sur la version 4 furent abandonnés en 2008 menant, en 2009, à une version 5 beaucoup moins ambitieuse qui apporta seulement quelques améliorations non controversées. Puis en 2015 vint la version 6, une mise à jour majeure incluant certaines des idées planifiées pour la version 4. Depuis, nous avons eu de nouvelles petites mises à jour chaque année.

Le fait que le langage évolue signifie que les navigateurs doivent constamment se mettre à jour, et si vous utilisez un vieux navigateur, il est possible qu’il ne supporte pas toutes les fonctionnalités. Les concepteurs du langage font attention pour n’apporter aucun changement qui puisse casser les programmes existants, cela fait en sorte que les nouveaux navigateurs peuvent quand même exécuter les vieux programmes. Dans ce livre, j’utilise la version 2017 de JavaScript.

Les navigateurs web ne sont pas les seules plateformes où JavaScript est utilisé. Certaines bases de données telles que MongoDB et CouchDB utilisent JavaScript comme langage de scripts et de requêtes. Plusieurs plateformes de programmation pour postes de travail et pour serveurs, comme le notable projet Node.js (le sujet du chapitre 20), fournissent un environnement pour programmer en JavaScript en dehors du navigateur.

I-D - Quoi faire avec le code ?

Le code est le texte qui constitue les programmes. La plupart des chapitres de ce livre contiennent beaucoup de code. Je crois que lire et écrire du code est une partie indispensable de l’apprentissage de la programmation. Essayez de ne pas simplement survoler les exemples – lisez-les attentivement et comprenez-les. Cela pourra sembler lent et confus au début, mais je vous promets que vous allez vous y habituer. La même chose vaut pour les exercices. Ne présumez pas que vous les comprenez tant que vous n’avez pas encore écrit une solution valide.

Je vous recommande de tester vos solutions aux exercices dans un interpréteur JavaScript. De cette façon, vous saurez immédiatement si ce que vous faites fonctionne, et, je le souhaite, serez tenté d’expérimenter et d’aller au-delà des exercices.

Lorsque vous lisez ce livre dans votre navigateur, vous pouvez éditer (et exécuter) tous les exemples de programmes en cliquant dessus.

Si vous désirez exécuter les programmes inscrits dans ce livre en dehors du site web du livre, certaines attentions seront requises. Plusieurs exemples sont complets et devraient fonctionner dans n’importe quel environnement JavaScript. Mais le code de certains des derniers chapitres est souvent écrit pour un environnement spécifique (le navigateur ou Node.js) et ne peut pas être exécuté ailleurs. De plus, certains chapitres décrivent de plus gros programmes, et les morceaux de code inclus sont dépendants d’autres ou de fichiers externes. Le bac à sable (SandBox) du site web fournit des liens vers des fichiers zip contenant tous les scripts et données nécessaires à l’exécution du code pour un chapitre donné.

I-E - Vue d’ensemble de ce livre

Ce livre contient essentiellement trois parties. Les douze premiers chapitres parlent du langage JavaScript. Les sept chapitres suivants concernent les navigateurs web et la manière dont JavaScript est utilisé pour les programmer. Finalement, deux chapitres sont dédiés à Node.js, un autre environnement dans lequel on peut programmer en JavaScript.

Dans le livre, il y a cinq projets de chapitres qui décrivent de plus grands exemples de programmes qui vous donneront un goût de ce qu’est la programmation. Par ordre d’apparition, nous travaillerons à construire un « robot de livraison », un « langage de programmation », un « jeu de plateforme », un « programme de dessin digital » et un « site web dynamique ».

La partie du livre traitant du langage commence avec quatre chapitres traitant de la structure de base du langage JavaScript. Ils introduisent les « structures de contrôle » (tel que le mot réservé while que vous avez vu dans cette introduction), les « fonctions » (écrire vos propres blocs de code), et les « structures de données ». Après cela, vous serez en mesure d’écrire de petits programmes. Ensuite, les chapitres 5 et 6 traitent des techniques pour utiliser les fonctions et les objets pour écrire du code abstrait et garder la complexité sous contrôle.

Après un premier chapitre du projet, la partie du livre dédiée au langage continue avec des chapitres sur la « gestion des erreurs et la résolution de bogues », les « expressions régulières » (un outil important pour travailler avec du texte), la « modularité » (une autre défense face à la complexité), et la « programmation asynchrone » (gérer les événements qui ont une durée). Le second chapitre du projet conclut cette première partie du livre.

La deuxième partie, les chapitres 13 à 19, décrit les outils auxquels le navigateur JavaScript a accès. Vous apprendrez à afficher des choses à l’écran (chapitres 14 et 17), répondre aux interactions de l’utilisateur (chapitre 15), et communiquer à travers le réseau (chapitre 18). On retrouve encore deux chapitres du projet dans cette partie.

Après cela, le chapitre 20 décrit Node.js, et le chapitre 21 construit un petit site web utilisant cet outil.

I-F - Conventions typographiques

Dans ce livre, le texte écrit dans une police monospace va représenter des éléments de programmes – parfois il s’agit d’extraits de code autonome, et parfois ils réfèrent à une partie d’un programme connexe. Les programmes (dont vous en avez déjà vu quelques-uns) sont écrits de la façon suivante :

1. function factorial(n) {

2. if (n == 0) {

3. return 1;

4. } else {

5. return factorial(n - 1) * n;

6. }

7. }

Parfois, pour montrer la sortie qu’un programme produit, la sortie attendue est écrite à la suite, avec deux barres obliques et une flèche en avant.

console.log(factorial(8));
// → 40320

Bonne lecture !

II - Valeurs, Types et Opérateurs

Sous la surface de la machine, le programme bouge. Sans effort, il se dilate et se contracte. En grande harmonie, les électrons se dispersent et se regroupent. Les formes sur l’écran ne sont que des ondulations sur l'eau. L'essence reste invisible en dessous.— Maître Yuan-Ma, Le Livre de la Programmation

À l’intérieur du monde de l'ordinateur, ce ne sont que des données. Vous pouvez lire des données, modifier des données, créer de nouvelles données — mais ce qui n'est pas une donnée ne peut pas être mentionné. Toutes ces données sont stockées comme de longues séquences de bits et sont donc fondamentalement identiques.

Les bits représentent n’importe quelle donnée et ont deux valeurs, habituellement décrits comme des zéros et des uns. À l’intérieur de l'ordinateur, ils prennent des formes telles qu'une charge électrique haute ou basse, un signal fort ou faible, ou un point brillant ou terne sur la surface d'un CD. N'importe quelle information discrète peut être réduite à une séquence de zéros et de uns, et donc représentée en bits.

Par exemple, nous pouvons exprimer le nombre 13 en bits. Cela fonctionne de la même façon qu'un nombre décimal, mais au lieu de dix chiffres différents, vous n'en avez que deux, et le poids de chacun s’accroît par un facteur 2 de droite à gauche. Voici les bits qui font le nombre 13, avec le poids des chiffres affiché en dessous d'eux :

1. 0   0   0   0   1   1   0   1

2. 128  64  32  16   8   4   2   1

C'est donc le nombre binaire 00001101. Ses chiffres non nuls représentent 8, 4 et 1, et totalisent 13.

II-A - Valeurs

Imaginez une mer de bits — un océan de bits. Un ordinateur moderne typique a plus de 30 milliards de bits dans son stockage de données volatiles (mémoire de travail). Le stockage non volatil (le disque dur ou équivalent) tend à en avoir plus par plusieurs ordres de magnitude.

Pour être capable de travailler avec de telles quantités de bits sans être perdu, nous devons les séparer en morceaux qui représentent des éléments d’information. Dans un environnement JavaScript, ces morceaux sont appelés valeurs. Bien que toutes ces valeurs soient faites de bits, elles jouent des rôles différents. Toute valeur a un type qui détermine son rôle. Certaines valeurs sont des nombres, certaines sont des morceaux de texte, certaines sont des fonctions, et ainsi de suite.

Pour créer une valeur, vous devez juste invoquer son nom. C'est pratique. Vous n'avez pas besoin de collecter des matériaux de construction pour vos valeurs ou payer pour elles. Vous en appelez une et vous l’avez immédiatement. Bien sûr, elles ne sont pas vraiment créées à partir de rien. Chaque valeur doit être stockée quelque part, et si vous voulez utiliser une gigantesque quantité d'entre elles au même moment, vous pouvez être à court de mémoire. Heureusement, cela n'est un problème que si vous avez besoin de toutes simultanément. Dès que vous n'utilisez plus une valeur, elle disparaîtra, laissant derrière elle ses bits pour être recyclés comme matériel de construction pour la prochaine génération de valeurs.

Ce chapitre introduit les éléments atomiques des programmes JavaScript, qui sont les types simples de valeurs et les opérateurs qui peuvent agir sur de telles valeurs.

II-B - Nombres

Les valeurs du type nombre sont, sans surprise, des valeurs numériques. Dans un programme JavaScript, elles sont écrites ainsi :

1. 13

Utilisez cela dans un programme, et cela entraînera la création du motif de bit pour le nombre 13 dans la mémoire de l’ordinateur.

JavaScript utilise un nombre fixe de bits, 64 d'entre eux, pour stocker valeur numérique unique. Il existe seulement un certain nombre de motifs que vous pouvez faire avec 64 bits, ce qui signifie que le nombre de différents nombres pouvant être représentés est limité. Avec N nombres décimaux, vous pouvez représenter nombres. De façon similaire, avec 64 chiffres binaires, vous pouvez représenter nombres différents, ce qui vaut environ 18 quintillions (un 18 suivi de 18 zéros). C'est beaucoup.

Auparavant, la mémoire de l’ordinateur était beaucoup plus petite, et les gens tendaient à utiliser des groupes de 8 ou 16 bits pour représenter leurs nombres. Il était facile de déborder (overflow) de si petits nombres par accident — pour finir avec un nombre qui ne peut pas être contenu dans le nombre donné de bits. Aujourd'hui, même les ordinateurs qui rentrent dans votre poche ont plein de mémoire, donc vous êtes libre d'utiliser des morceaux de 64 bits, et vous devez seulement vous inquiéter quand vous traitez avec des nombres réellement astronomiques.

Cependant, les nombres de moins de 18 quintillions ne peuvent pas tous être contenus dans un nombre JavaScript. Ces bits stockent aussi des nombres négatifs, donc un bit indique le signe du nombre. Un problème plus important est que les nombres non entiers doivent aussi être représentés. Pour faire cela, certains bits sont utilisés pour stocker la position du séparateur décimal. Le vrai nombre entier maximal qui peut être stocké est plus autour de 9 quadrillions (15 zéros) — ce qui est toujours plaisant.

Les nombres fractionnaires sont écrits avec un point.

1. 9.81

Pour de très grands ou très petits nombres, vous pouvez aussi utiliser la notation scientifique en ajoutant un e (pour exposant), suivi par l'exposant du nombre.

1. 2.998e8

C'est 2.998 × 10^8 = 299 800 000.

Les calculs avec les nombres entiers (aussi appelés entiers) plus petits que le susmentionné 9 quadrillions sont garantis d’être toujours précis. Malheureusement, les calculs avec les nombres fractionnaires ne le sont généralement pas. Tout comme π (pi) ne peut pas être exprimé précisément par un nombre fini de chiffres décimaux, beaucoup de nombres perdent en précision quand seulement 64 bits sont disponibles pour les stocker. C'est dommage, mais cela ne cause des problèmes pratiques que dans des situations spécifiques. L’important est d’en prendre conscience et de traiter les nombres numériques fractionnaires comme approximations, et non pas comme des valeurs précises.

II-B-1 - Arithmétique

La principale chose à faire avec les nombres c'est de l’arithmétique. Les opérations arithmétiques comme l'addition ou la multiplication prennent deux valeurs numériques et produisent un nouveau nombre à partir d'eux. Voici à quoi cela ressemble en JavaScript :

1. 100 + 4 * 11

Les symboles + et * sont appelés opérateurs. Le premier correspond à l'addition, et le second correspond à la multiplication. Mettre un opérateur entre deux valeurs l'appliquera à ces valeurs et produira une nouvelle valeur.

Mais est-ce que l'exemple signifie « ajouter 4 et 100, et multiplier le résultat par 11 », ou est-ce que la multiplication est réalisée avant l'addition ? Comme vous avez dû le deviner, la multiplication est faite en premier. Mais comme en arithmétique, vous pouvez changer cela en encadrant l'addition avec des parenthèses.

1. (100 + 4) * 11

Pour la soustraction, il y a l’opérateur -, et la division peut être faite avec l’opérateur /.

Quand 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 vient avant l'addition. L’opérateur / à la même précédence que *. De même pour + et -. Quand plusieurs opérateurs avec la même précédence apparaissent les uns après les autres, comme dans 1 - 2 + 1, ils sont appliqués de gauche à droite : (1 - 2) + 1.

Ces règles de précédence ne sont pas quelque chose dont vous devez vous inquiéter. En cas de doute, ajouter simplement des parenthèses.

Il y a un autre opérateur arithmétique, que vous ne reconnaîtrez peut-être pas immédiatement. Le symbole % est utilisé pour représenter l’opération de reste. X % Y est le reste de la division de X par Y. Par exemple, 314 % 100 produit 14, et 144 % 12 retourne 0. La précédence de l’opérateur de reste est le même que pour la multiplication et la division. Vous verrez aussi souvent cet opérateur être appelé modulo.

II-B-2 - Nombres spéciaux

Il y a trois valeurs spéciales en JavaScript qui sont considérées comme des nombres, mais ne se comportent pas comme des nombres normaux.

Les deux premières sont Infinity et -Infinity qui représentent les infinis positif et négatif. Infinity - 1 est toujours Infinity, et ainsi de suite. Cependant, ne faites pas trop confiance aux calculs basés sur l’infini. Cela n'est pas mathématiquement correct, et cela mènera rapidement au prochain nombre spécial : NaN.

NaN signifie « not a number » (pas un nombre), cependant c'est une valeur de type nombre. Vous obtiendrez ce résultat quand, par exemple, vous essayez de calculer 0 / 0 (zéro divisé par zéro), Infinity - Infinity, ou n'importe quelle autre opération numérique qui ne retourne pas de résultat significatif.

II-C - Chaînes

Le type de donnée de base suivant est la chaîne (string). Les chaînes sont utilisées pour représenter du texte. Elles sont écrites en encadrant leur contenu avec des guillemets.

1. `Down on the sea`

2. "Lie on the ocean"

3. 'Float on the ocean'

Vous pouvez utiliser des guillemets simples, des guillemets doubles, ou des guillemets obliques pour marquer les chaînes, du moment que le début et la fin de la chaîne concordent.

Presque tout peut être mis entre guillemets, et JavaScript en fera une chaîne. Mais quelques caractères sont plus difficiles. Vous pouvez imaginer comment mettre des guillemets entre guillemets peut être compliqué. Les sauts de ligne (les caractères que vous avez quand vous pressez ENTER) peuvent être inclus sans échappement seulement si la chaîne est entre guillemets obliques (``).

Pour rendre possible d'inclure de tels caractères dans une chaîne, la notation suivante est utilisée : dès qu'un antislash (\) est trouvé dans un texte entre guillemets, il indique que le caractère suivant a une signification spéciale. Ceci est appelé échapper le caractère. Un guillemet qui est précédé par un antislash ne terminera pas la chaîne, mais en fera partie. Quand un caractère n apparaît après un antislash, il est interprété comme un saut de ligne. De façon similaire, un t après un antislash signifie un caractère tabulation. Prenez la chaîne suivante :

1. "This is the first line\nAnd this is the second"

Le texte réel contenu est :

1. This is the first line

2. And this is the second

Les chaînes, aussi, doivent être modelées comme des séries de bits pour pouvoir exister dans l'ordinateur. La façon dont JavaScript le fait est basée sur la norme Unicode. Cette norme assigne virtuellement un nombre à chaque caractère dont vous pourrez avoir besoin, incluant les caractères du grec, arabe, japonais, arménien, et ainsi de suite. Si nous avons un nombre pour chaque caractère, une chaîne peut être décrite comme une séquence de nombres.

Et c'est ce que JavaScript fait. Mais il y a une complication : la représentation JavaScript utilise 16 bits par élément de chaîne, ce qui décrit jusqu'à caractères différents. Mais Unicode définit plus de caractères que cela — à peu près deux fois plus, à ce stade. Donc certains caractères, tels que beaucoup d’émoticônes, prennent jusqu'à deux « positions de caractère » dans les chaînes JavaScript. Nous y reviendrons au Chapitre 5.

Les chaînes ne peuvent pas être divisées, multipliées, ou soustraites, mais l’opérateur + peut être utilisé sur elles. Il n'additionne pas, mais fait plutôt une concaténation — il colle deux chaînes ensemble. La ligne suivante produira la chaîne "concatène" : :

1. "con" + "cat" + "è" + "ne"

Les valeurs chaîne ont un nombre de fonctions (méthodes) qui leur sont associées et qui peuvent être utilisées pour réaliser des opérations sur elles. J'en dirai plus à propos de celles-ci dans le Chapitre 4.

Les chaînes écrites avec des guillemets simples ou doubles se comportent de façon très similaire — la seule différence est le type de guillemet que vous avez besoin d’échapper à l’intérieur. Les chaînes avec guillemets obliques, habituellement appelées littéraux de gabarits, peuvent faire quelques trucs supplémentaires. En dehors de pouvoir étendre des lignes, elles peuvent aussi intégrer d'autres valeurs.

1. console.log(la moitié de 100 est ${100 / 2)

Quand vous écrivez quelque chose à l’intérieur de ${} dans un littéral de gabarit, son résultat sera calculé, converti en chaîne, et inclus à cette position. Cet exemple produit "la moitié de 100 est 50".

II-D - Opérateurs unaires

Tous les opérateurs unaires ne sont pas des symboles. Certains sont écrits avec des mots. Un exemple est l’opérateur typeof qui produit une valeur chaîne nommant le type de la valeur que vous lui avez donnée.

1. console.log(typeof 4.5)

2. // → number

3. console.log(typeof "x")

4. // → string

Nous utiliserons console.log dans le code de l'exemple pour indiquer que nous voulons voir le résultat de quelque chose qui a été évalué. Plus d'information dans le chapitre suivant.

Les opérateurs qui ont été présentés opèrent tous avec deux valeurs, mais typeof n'en prend qu'une seule. Les opérateurs qui utilisent deux valeurs sont appelés opérateurs binaires, alors que ceux qui en prennent une sont appelés opérateurs unaires. L’opérateur moins peut être utilisé à la fois comme un opérateur binaire et comme un opérateur unaire.

1. console.log(- (10 - 2))

2. // → -8

II-E - Valeurs booléennes

Il est souvent utile d'avoir une valeur qui distingue entre deux possibilités telles que « oui » et « non », ou « on » et « off ». Pour ce faire, JavaScript a un type booléen qui a seulement deux valeurs, true (vrai) et false (faux) qui sont écrites telles quelles.

II-E-1 - Comparaison

Voici une façon de produire des valeurs booléennes :

1. console.log(3 > 2)

2. // → true

3. console.log(3 < 2)

4. // → false

Les signes > et < sont respectivement les symboles traditionnels pour « plus grand que » et « plus petit que ». Ce sont des opérateurs binaires. De leur application résulte une valeur booléenne indiquant s'ils sont vrais ou non.

Les chaînes peuvent être comparées de la même façon.

1. console.log("Aardvark" < "Zoroaster")

2. // → true

La manière dont les chaînes sont ordonnées est grosso modo alphabétique, mais pas vraiment ce que vous vous attendriez à voir dans un dictionnaire : les lettres majuscules sont toujours « moins » que les minuscules, donc "Z" < "a", et les caractères non alphabétiques (!,-, et autres) sont aussi inclus dans l'ordre. Lors de la comparaison de chaînes, JavaScript parcourt les caractères de gauche à droite, comparant les codes Unicode un par un.

Les autres opérateurs similaires sont >= (plus grand ou égal à), <= (plus petit ou égal à), == (égal à), et != ( différent de ).

1. console.log("Itchy" != "Scratchy")

2. // → true

3. console.log("Pomme" == "Orange")

4. // → false

Il y a seulement une valeur en JavaScript qui n'est pas égale à elle-même, et c'est NaN (« not a number » qui signifie en français « pas un nombre »).

1. console.log(NaN == NaN)

2. // → false

NaN est supposé représenter le résultat d'un calcul absurde, et en tant que tel, il n'est pas égal au résultat de quel qu'autre calcul absurde.

II-E-2 - 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 : et, ou et non. Ils peuvent être utilisés pour « raisonner » à propos des booléens.

L’opérateur && représente la logique et. C'est un opérateur binaire, et son résultat est vrai (true) seulement si les deux valeurs qui lui sont données sont vraies.

1. console.log(true && false)

2. // → false

3. console.log(true && true)

4. // → true

L’opérateur || représente la logique ou. Il retourne vrai (true) si l'une ou l'autre des valeurs qui lui sont données est vraie.

1. console.log(false || true)

2. // → true

3. console.log(false || false)

4. // → false

Non est écrit avec un point d'exclamation (!). C'est un opérateur unaire qui inverse la valeur qui lui est passée —!true retourne false et !false retourne true.

Lorsque l'on mélange ces opérateurs booléens avec les opérateurs arithmétiques et les autres, il n'est pas toujours évident de savoir quand les parenthèses sont nécessaires. En pratique, vous devez connaître l’ordre de priorité des opérateurs que nous avons vu jusque-là, || a la précédence la plus basse, puis vient &&, et puis les opérateurs de comparaison (>,==, ainsi de suite), et puis le reste. Cet ordre a été choisi de telle manière que, dans une expression typique comme la suivante, aussi peu de parenthèses que possible sont nécessaires :

1. 1 + 1 == 2 && 10 * 10 > 50

Le dernier opérateur logique dont je vais discuter n'est ni unaire, ni binaire, mais ternaire, opérant sur trois valeurs. Il est écrit avec un point d'interrogation et un deux-points, comme suit :

1. console.log(true ? 1 : 2);

2. // → 1

3. console.log(false ? 1 : 2);

4. // → 2

Celui-ci est appelé opérateur conditionnel (ou quelquefois juste opérateur ternaire puisque c'est le seul opérateur de ce type dans le langage). La valeur à gauche du point d'interrogation « choisit » laquelle des deux autres valeurs sera retournée. Quand elle est vraie, elle choisit la valeur du milieu, et quand elle est fausse, elle choisit la valeur de droite.

II-F - Valeurs vides

Il y a deux valeurs spéciales, écrites null et undefined, qui sont utilisées pour dénoter l'absence de valeur significative. Elles sont elles-mêmes des valeurs, mais elles ne comportent pas d'information.

Beaucoup d’opérations du langage qui ne produisent pas de valeur significative (vous verrez cela plus tard) retournent undefined simplement parce qu'elles doivent retourner une valeur.

La différence de sens entre undefined et null est un accident de conception de JavaScript, et cela n'a pas d'importance la plupart du temps. Dans les cas où vous êtes effectivement concerné par ces valeurs, je recommande de les considérer comme interchangeables.

II-G - Conversion de type automatique

Dans l'Introduction, j'ai mentionné que JavaScript se met en quatre pour accepter presque tous les programmes que vous lui donnez, même ceux qui font des choses bizarres. Ceci est bien démontré avec les expressions suivantes :

1. console.log(8 * null)

2. // → 0

3. console.log("5" - 1)

4. // → 4

5. console.log("5" + 1)

6. // → 51

7. console.log("five" * 2)

8. // → NaN

9. console.log(false == 0)

10. // → true

Quand un opérateur est appliqué sur le « mauvais » type de valeur, JavaScript va discrètement convertir cette valeur dans le type dont il a besoin, utilisant un jeu de règles qui souvent ne sont pas celles que vous voulez ou attendez. C'est appelé « conversion de type ». Le null de la première expression devient 0, et le "5" de la seconde expression devient 5 (d'une chaîne à un nombre). Mais dans la troisième expression, + essaye de concaténer avant de faire l’opération numérique, donc le 1 est converti en "1" (d'un nombre à une chaîne).

La conversion d’une valeur qui ne correspond pas à un nombre de façon évidente (tel que "five" ou undefined) en un nombre, donne la valeur NaN. De plus, les opérations arithmétiques sur NaN continuent de produire un NaN, donc si vous vous retrouvez à obtenir une valeur NaN à un endroit inattendu, regardez au niveau des conversions de type accidentelles.

Lors de la comparaison de valeurs de même type utilisant ==, le résultat est facile à prédire : vous devriez obtenir true quand les deux valeurs sont les mêmes, sauf dans le cas de NaN. Mais si les types diffèrent, JavaScript utilise un jeu de règles compliqué et confus pour déterminer quoi faire. Dans la plupart des cas, il essaie juste de convertir une des valeurs dans le type de l'autre valeur. Cependant, quand null ou undefined apparaissent d'un côté ou de l'autre de l’opérateur, il produit true seulement si les deux côtés sont soit null ou undefined.

1. console.log(null == undefined);

2. // → true

3. console.log(null == 0);

4. // → false

Ce comportement est souvent utile. Quand vous voulez tester si une valeur a une vraie valeur plutôt que null ou undefined, vous pouvez la comparer à null avec l’opérateur == (ou !=).

Mais que faire si vous voulez tester si quelque chose réfère précisément à la valeur false ? Des expressions comme 0 == false et "" == false sont aussi vraies à cause de la conversion de type automatique. Quand vous ne voulez aucune conversion de type se produire, il y a deux opérateurs additionnels : === et !===. Le premier teste si une valeur est précisément égale à l'autre, et le second teste si elle est précisément non égale. Donc "" === false est faux comme attendu.

Je recommande d'utiliser les opérateurs de comparaison à trois caractères de manière défensive pour éviter d’être piégé par les conversions de type inattendues. Mais quand vous êtes certain que les types de chaque côté sont les mêmes, il n'y a pas de problème à utiliser les opérateurs plus courts.

II-G-1 - Court-circuiter les opérateurs logiques

Les opérateurs && et || gèrent les valeurs de types différents d'une façon particulière. Ils convertiront la valeur à leur gauche en type booléen afin de décider quoi faire, mais en fonction de l’opérateur et du résultat de cette conversion, ils retourneront soit la valeur d’origine de gauche ou la valeur de droite.

Par exemple, l’opérateur || retournera la valeur à sa gauche quand elle peut être convertie en true, sinon, il retournera la valeur de droite. Cela a l'effet attendu quand les valeurs sont booléennes et fait quelque chose d'analogue pour les valeurs d'autres types.

1. console.log(null || "user")

2. // → user

3. console.log("Agnes" || "user")

4. // → Agnes

Nous pouvons utiliser cette fonctionnalité comme un moyen de revenir à une valeur par défaut. Si vous avez une valeur qui peut être vide, vous pouvez mettre || après avec sa valeur de remplacement. Si la valeur initiale peut être convertie en false, vous aurez la valeur de remplacement. Les règles pour convertir les chaînes et les nombres en booléens définissent que 0,NaN, et la chaîne vide ("") comptent comme false, alors que toutes les autres valeurs comptent comme true. Donc 0 || -1 produit -1, et "" || "!?" retourne « "!?" »

L’opérateur && fonctionne de la même façon, mais dans l'autre sens. Quand la valeur à sa gauche est quelque chose qui se convertit en false, il retourne cette valeur, sinon il retourne la valeur à sa droite.

Une autre propriété importante de ces deux opérateurs est que la partie à leur droite est évaluée seulement quand cela est nécessaire. Dans le cas de true || X quel que soit X — même si c'est une partie de programme qui fait quelque chose de terrible — le résultat sera vrai, et donc X n'est jamais évalué. De même pour false && X qui est faux et qui ignore X. Ceci est appelé

évaluation en court-circuit.

L’opérateur conditionnel fonctionne d'une manière similaire. Parmi la seconde et la troisième valeur, seule celle qui est sélectionnée est évaluée.

II-H - Résumé

Nous avons vu quatre types de valeur JavaScript dans ce chapitre : nombres, chaînes, booléens, et valeurs non définies.

De telles valeurs sont créées en tapant leur nom (true, null) ou valeur (13, "abc"). Vous pouvez combiner et transformer des valeurs avec des opérateurs. Nous avons vu les opérateurs binaires pour l’arithmétique (+, -, *, / et %), la concaténation de chaîne (+), la comparaison (==, !=, ===, !==, <, >, <=, >=), et la logique (&&, || ) , de même que plusieurs opérateurs unaires (- pour opposer un nombre, ! pour opposer logiquement, et typeof pour trouver le type d'une valeur) et un opérateur ternaire (?:) pour choisir une valeur parmi deux à partir d'une troisième valeur.

Cela vous donne assez d'information pour utiliser JavaScript comme une calculatrice de poche, mais pas beaucoup plus. Le prochain chapitre commencera à intégrer ces expressions ensemble pour faire des programmes de base.