Objectifs: Le but de ce TD est de vous faire expérimenter les constructions de base du langage JavaScript (types simples, déclarations de variables, instructions de contrôle, itérations) qui sont très proches syntaxiquement de celles utilisées par le langage C. Les programmes que vous aurez à écrire ne font appel qu'aux constructions de base du langage JavaScript (Core JavaScript) mis à part pour la lecture de valeurs au clavier. C'est pourquoi afin de simplifier leur écriture et leur exécution, vous utiliserez l'environnement Node.js qui vous affranchira de l'intégration de vos scripts dans du code HTML et de l'utilisation d'un navigateur.

Les exercices proposés dans ce TP sont indépendants et sont organisés selon 4 thèmes thèmes : expressions , instructions conditionnelles, itérations, fonctions. Une 5ème partie propose un ensemble d'exercices que vous pourrez réaliser de manière facultative pour vous entrainer.

Ressources utiles

Prenez dès maintenant de bonnes habitudes de codage JavaScript. Il vous est demandé de respecter impérativement les 3 règles ci-dessus.

  1. tout programme source JavaScript doit avoir comme suffixe .js.
  2. Les noms de variables et de fonctions sont définis par un identificateur débutant par une minuscule (camelCase).
  3. Les programmes doivent être correctement indentés. (Utilisez l'outil d'identation automatique de VSCode !)

1. Prise en main de l'environnement de développement

Avant toute chose, vérifiez que Node.js est bien installé sur votre machine. Pour cela ouvrez un terminal et tappez la commande node --version, le numéro de la version de Node.js installée sur votre machine est alors affiché, par exemple v18.14.2.

Si la commande node n'est pas reconnue, vous devez télécharger et installer Node.js avant de continuer.

1.1 Créer et exécuter un programme JavaScript dans VSCode

Pour la réalisation de ce TP vous avez besoin d'un éditeur de texte et d'un environnement Javascript (Node.js). Pour exécuter un programme JavaScript contenu dans un fichier monProgramme.js il suffit d'ouvrir un terminal dans le répertoire contenant ce fichier et d'éxécuter la commande node monProgramme.js

Cependant il est possible de tout faire depuis l'IDE VScode comme vous allez pouvoir l'expérimenter dans l'exercice qui suit

1) Creez un fichier JavaScript HelloWorld.js

Création d'un fichier JavaScript avec VSCode

2) Editer le fichier HelloWorld.js

Dans HelloWorld.js tappez le code suivant

console.log("Hello World !");

VScode utilise IntelliSense pour l'édition du code et offre de nombreuses possibilités d'autocomplétion du code comme indiqué sur la figure ci dessous.

Autocomplétion du code JavasScript dans VSCode

3) Exécuter le programme HelloWorld.js

Une fois votre code écrit et enregistré vous pouvez directement l'exécuter en ouvrant un terminal dans VSCode et en invoquant l'interpréteur de Node.js

Exécution d'un fichier JavaScript avec Node.js depuis VSCode

1.2 Utiliser les modules (packages) Node

1.2.1 Lire des données au clavier avec readline-sync

console.log est une fonction standard de JavaScript qui permet d'afficher du texte sur la console de votre environnement d'exécution JavaScript (que ce soit un navigateur ou Node.js). Par contre, Core Javascript tel qu'il est défini par le standard ECMAScript ne définit pas de moyen de saisir des données à partir du clavier. La manière de procéder va dépendre de votre environnement d'éxécution. En ce qui concerne Node.js, nous allons utiliser un module complémentaire (readline-sync) qu'il va falloir installer à l'aide de npm, le gestionnaire de paquets (ou modules) officiel de Node.js (voir Node.js NPM).

Installation et utilisation du module readline-sync pour les lectures au clavier
  1. Installez le module readline-sync pour pouvoir l'utiliser dans vos programmes

  2. Constatez que Node.js a créé dans votre répertoire TP05 deux fichier de configuration package.json et package.lock.json et un répertoire node_modules qui contient le code du modules realine-async et des autres modules dont ce dernier dépend.
  3. Importez le module à l'aide d'une instruction require que vous placerez au debut de votre programme

    const readline = require('readline-sync');
  4. ensuite pour invoquer l'une des fonctions du module il suffit de préfixer l'appel par readline.. Par exemple :

    let prenom = readline.question("entrez votre prénom ");

    permet d'invoquer la fonction question qui affiche un message sur la console et attend un réponse de l'utilisateur. Une fois que l'utilisateur a saisi sa réponse la valeur de celle-ci est renvoyée et ici est stockée dans la variable prenom.

    readline-sync propose différentes fonctions (méthodes) selon la nature de la valeur que vous voulez saisir.

    • question() qui renvoie une chaîne de caractères (valeur de type string)
    • questionInt() qui renvoie une valeur entière (valeur de type number)
    • questionFloat() qui renvoie une valeur réelle (valeur de type number)

    Se référer à la documentation de readline-sync pour voir le detail des ces fonctions et leurs différents paramètres d'appel.

1.2.2 Modules CommonJS vs. Modules ES6 (ECMA Script 6)

Lorsque en 2009 Node.js a été créé, il n'existait pas de système de modules standardisé pour JavaScript. Pour combler ce vide et fournir un moyen de modulariser le code, l'équipe de Node.js a développé son propre système : CommonJS. C'est CommonJS que nous avons utilisé dans l'exercice précédent pour importer readline-sync avec l'instruction require.

En 2015 la spécification ES6 (ECMA Script 6) qui définit la norme JavaScript a, elle aussi, intégré la notion de modules mais avec une syntaxe différente de celle de CommonJS. Ces modules ES6 (également connus sous le nom de modules ECMAScript ou ESM) présentent des avantages tels que l'analyse statique, un meilleur support pour le chargement asynchrone et une syntaxe standardisée à travers les environnements JavaScript (côté client et serveur)

Node.js prend désormais en charge les deux systèmes de modules (CommonJS et ESM). Cependant pour assurer la compatibilité rétroactive avec le grand nombre de projets et de modules Node.js déjà existants et développés en utilisant CommonJS, Node.js a conservé CommonJS comme système de modules par défaut.

Modifiez votre programme HelloWorld.js pour utiliser la syntaxe ESM (ES Modules)

  1. Dans HelloWorld.js remplacez

    const readline = require('readline-sync');   // importation du module readline-sync avec CommonJS

    par

    import readline from 'readline-sync';   // importation du module readline-sync avec ESM
  2. Essayez d'exécuter à nouveau votre programme et constatez qu'une erreur se produit

    C'est normal ! Comme dit précédemment, Node.js supporte par défaut la syntaxe CommonJS, pour travailler avec la syntaxe ESM (modules ES6) deux possibilité vous sont proposées

    • soit utiliser l'extension de fichier .mjs pour les fichiers sources utilisant la syntaxe ESM

    • soit définir dans votre fichier package.json.

    Nous allons adopter la deuxième solution.

  3. Modifiez le fichier package.json pour y ajouter "type": "module" après la déclaration des dépendances

  4. Après avoir sauvegardé package.json réexécutez votre programme HelloWrorld.js et constatez que maintenant l'instruction import est reconnue et que le programme fonctionne correctement.

Remarque : si maintenant vous vouliez écrire du code JavaScript en utilisant la syntaxe Common.js, il faudrait utiliser l'extension .cjs au lieu de .js pour votre fichier source.

2. Expressions

Exercice 1 : Conversion de températures

En utilisant la formule \(tempC = (5/9)(tempF-32)\) écrire en langage JavaScript un programme degres.js qui lit une température exprimée en degrés Fahrenheit et affiche sa valeur en degrés centigrades ou degrés Celsius.

Exemples d'exécution du programme (en vert les valeurs introduites par l'utilisateur) :

P:\TW\TP05>node degres.js
donnez une temperature en Fahrenheit : O.O
cette temperature equivaut a -17.8 degres Celsius
P:\TW\TP05>node degres.js
donnez une temperature en Fahrenheit : 60.0
cette temperature equivaut a 15.6 degre Celsius
P:\TW\TP05>

Par défaut, lorsqu'un nombre flottant est affiché sur la console, tous les chiffres qu'il contient après le séparateur décimal apparaissent. Ainsi le code

let x = 17/7;
console.log("x = " + x);

donne l'affichage suivant

x = 2.4285714285714284

Il est néanmoins possible de formatter les nombres pour fixer le nombre de chiffres à conserver après le point décimal à l'aide de la méthode toFixed (voir w3schools ou MDN)

Exercice 2 : Conversion de durées

Ecrire un programme hjms.js en langage JavaScript qui pour un nombre de secondes donné calcule et affiche son équivalent en nombre de jours, d'heures, de minutes et de secondes.

exemples d'exécution du programme :

P:\TW\TP05>node hjms 
donnez une durée en secondes : 235789
cette durée equivaut à 2 jours 17 heures 29 minutes 49 secondes  
P:\TW\TP05>node hjms 
donnez une durée en secondes : 567231 
cette durée équivaut à 6 jours 13 heures 33 minutes et 51 secondes 
P:\TW\TP05>

L'opérateur % (modulo) permet d'obtenir le reste de la division entière de deux nombres. Par exemple

console.log("17 % 7 --> " + 17 % 7);
console.log("17 / 7 --> " + 17/7);

donne l'affichage suivant

17 % 7 --> 3
17 / 7 --> 2.4285714285714284

Pour obtenir la division entière de 17 par 7 (qui vaut 2) il faut passer par la méthode Math.floor (voir w3schools ou MDN)

3. Instructions conditionnelles

Exercice 1 : Améliorer le programme de conversion de durées

Si ce n'est déjà fait, améliorez votre programme hjms.js de sorte que lorsqu'une valeur (nombre de jours, d'heures , de minutes ou de secondes) est nulle elle n'apparaisse pas dans l'affichage, et que si elle vaut 1 l'unité soit affichée au singulier (sans s) comme dans l'exemple ci-dessous.

P:\TW\TP05>node hjms 
donnez une durée en secondes : 3621 
Cette durée equivaut à 1 heure 21 secondes 
P:\TW\TP05>

Exercice 2 : Classer 3 nombres

Ecrire un programme troisNombres.js qui lit 3 nombres au clavier et les affiche sur la console dans l'ordre croissant (du plus petit au plus grand).

P:\TW\TP05>node troisNombres
1er nombre : 14
2ème nombre : 10
3ème nombre : 17
les nombres dans l'ordre croissant : 10 14 17
P:\TW\TP05>

4. Itérations

Exercice 1 : Affichage de motifs - escaliers

Ecrire un programme qui affiche un motif triangulaire dont la taille est fixée par une valeur lue au clavier.

Exemple de trace d'exécution:

P:\TW\TP05>node  triangle1
donnez taille du motif : 7
*
**
***
****
*****
******
*******
P:\TW\TP05>

a) écrire un programme triangle1.js affichant ce motif en utilisant uniquement des instructions tant que (while()).

b) écrire un programme triangle2.js affichant ce motif en utilisant uniquement des instructions pour (for).

Exercice 2 : Affichage de motifs - pyramides

Même exercice que le précédent mais le motif affiché n'est plus un triangle mais une pyramide (voir ci-dessous) et le choix des instructions pour le réaliser est laissé à votre jugement.

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\TW\TP05>node pyramide
donnez taille du motif : 7
      *
     ***
    *****
   *******
  *********
 *********** 
*************
P:\TW\TP05>

5. Fonctions

Exercice 1 : Moyenne olympique

Ecrivez un programme moyenneOlympique.js qui lit au clavier une séquence de nombres réels positifs ou nuls (correspondant à des notes comprises entre 0 et 10), séquence terminée par la valeur -1, et calcule la moyenne olympique de ces valeurs, c'est à dire la moyenne des notes sans prendre en compte la note la plus élevée ni la note la moins élevée (c'est ce qui se passe dans les compétitions de gymnastique ou de patinage artistique pour limiter les abus dans la notation).

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\TW\TP05>node moyenneOlympique.js
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.89
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 8.76
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 8.45
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 9.10
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 14.75
Valeur incorrecte. Recommencez !
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.75
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 9.30
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : 7.50
Donner un note entre 0 et 10 (-1 pour terminer la saisie) : -1

Nombre de notes saisies 7
La note la plus élevée (9.3)et la note plus basse (7.5) ont été retirées
La moyenne olympique est : 8.39
P:\TW\TP05>

Pour l'écriture de ce programme, vous devez utiliser uniquement des variables de type primitif et ne pas vous servir d'un tableau ou d'une liste

Pour la lecture des notes, vous écrirez une fonction lireNote qui effectue la saisie d'une note et vérifie que celle-ci est correcte. Les traitements effectués par cette fonctions sont les suivants:

  1. afficher le message d'invite (prompt) indiquant l'intervalle de validité des notes et la valeur de fin de séquence.
  2. lecture d'une valeur
  3. vérification que cette valeur est bien dans l'intervalle de valeurs autorisées ou est égale à la valeur de fin de séquence. Si c'est le cas la valeur lue est retournée, sinon un message d'erreur est affiché est une nouvelle valeur est demandée à l'utilisateur.

Exercice 2: Créer et utiliser un module ESM

Dans les programmes degres.js et hjms.js, vus lors de l'exercice 1, il n'est possible de faire qu'une seule saisie. Si l'utilisateur veut effectuer plusieurs conversions, il doit relancer l'exécution du programme. On souhaite modifier le comportement de ces programmes de manière à ce que l'utilisateur puisse renouveler le traitement jusqu'à ce qu'il dise explicitement qu'il désire terminer l'exécution. Le déroulement de l'exécution de ces programmes serait alors le suivant :

P:\TW\TP05>node degres2.js
donnez une température en degrés Fahrenheit : 32
la température en degrés Celsius est 0.00
voulez-vous recommencer ?  (O/N): O
donnez une température en degrés Fahrenheit : 45
la température en degrés Celsius est 7.22
voulez-vous recommencer ?  (O/N): 33
désolé nous n'avons pas compris votre réponse 
voulez-vous recommencer ?  (O/N): o
donnez une température en degrés Fahrenheit : 23
la température en degrés Celsius est -5.00
voulez-vous recommencer ?  (O/N): n
Au revoir !

P:\TW\TP05>node hjms
entrez une durée (en sec.) : 345678
Cette durée equivaut à 4 jours 1 minute 18 secondes 
encore ?  (O/N): o
entrez une durée (en sec.) : 3567912
Cette durée equivaut à 41 jours 7 heures 5 minutes 12 secondes 
encore ?  (O/N): p
désolé nous n'avons pas compris votre réponse 
encore ?  (O/N): n
P:\TW\TP05>

a) Pour cela vous allez écrire une fonction encore qui affiche un message demandant à l'utilisateur si il veut poursuivre ou non le traitement et qui selon la valeur saisie retourne un booléen (true si il veut poursuivre, false sinon). .

Dans un premier temps écrivez et testez cette fonction dans le programme degres.js.

b) Ensuite pour pouvoir utiliser cette fonction dans d'autres programmes (par exemple hjms.js) il vaut mieux l'isoler dans un module que vous pourrez importer à la manière du module readline-async utilisé pour les lectures au clavier. Pour cela procédez comme suit :

  1. créez un fichier utils.js
  2. couper le code la function encore dans le fichier degres.js et collez le dans utils.js
  3. modifiez la signature de la fonction en précédant sa déclaration d'une directive export comme indiqué ci dessous
    // pour utiliser le module readline
    import readline from 'readline-sync';
    
    export function encore(message) {
       .... les instructions de la fonction
    }
  4. pour utiliser la fonction dans un autre de vos programmes, utilisez une instruction import comme pour readline-async pour importer le module
    import readline from "readline-sync"; // pour utiliser le module readline-sync
    import { encore } from "./utils.js"; // pour utiliser la fonction encore du module utils

Modifiez les programmes degres.js et hjms.js pour permettre à l'utilisateur d'effectuer autant de traitements qu'il le souhaite.

6. Exercices supplémentaires

Les exercices de cette partie sont facultatifs, faites les pour vous entrainer lorsque vous aurez du temps

Exercice 1 : Tester si un nombre est premier

Un nombre est n premier si il a seulement deux diviseurs : 1 et n.

Ecrire un programme Premier.js qui permet de tester si un nombre introduit par l'utilisateur est premier ou non.

Exemple de trace d'exécution (en vert les valeurs introduites par l'utilisateur):

P:\TW\TP05>node Premier
donnez un entier positif  : 7
7 est un nombre premier

Voulez-vous essayer un autre nombre O/N ? o

donnez un entier positif  : 25
25 n'est pas un nombre premier, il est divisible par 5

Voulez-vous essayer un autre nombre O/N ? n
Au revoir
P:\TW\TP05>

Exercice 2 : Suite de Fibonacci

La suite de Fibonacci est définie par la formule de récurrence suivante:

u0 = 0
u1 = 1
un = un-1 + un-2 (pour n >= 3)

a) Ecrire un programme Fibo1.js qui permet de calculer le nième terme de la suite de Fibonacci, n étant fixé par l'utilisateur.

b) Ecrire un programme Fibo2.js qui permet d'obtenir la valeur et le rang du premier terme de cette suite supérieure à une valeur donnée par l'utilisateur.

Exercice 3 : Prix d'un lot

Le jeu consiste à découvrir par essais successifs le prix d'un lot . Pour chaque essai, le joueur reçoit un message : "Trop grand", "Trop petit" ou "BRAVO ! Vous avez trouvé en K essais". Le jeu est fini quand le joueur a trouvé le prix du lot.

Exercice 3.1 : Ecrivez un programme JavaScript PrixLot1.js qui joue le rôle de meneur de jeu ; l'exécution de ce programme vous fera tenir le rôle du joueur. Le programme Prixlot1doit définir le prix du lot en tirant un entier aléatoire entre 1 et 1000 et dialoguer avec le joueur pendant le jeu.

Pour choisir un nombre au hasard on utilisera la méthode random de la classe Math qui retourne un réel (double) tiré au hasard et de manière uniforme dans l'intervalle [0 1].

exemple :

double x; x = Math.random();

exemple d'exécution du programme PrixLot1

P:\TW\TP05>node PrixLot1
Le but est de chercher un prix entre 0 et 1000
Tapez un prix : 566 
Trop grand
Tapez un prix : 400 
Trop grand
Tapez un prix : 150 
Trop petit
Tapez un prix : 200
Trop petit
Tapez un prix : 214
BRAVO ! Vous avez gagné en 5 essais
P:\TW\TP05>

Exercice 3.2 : Copier dans le fichier PrixLot2.js le fichier PrixLot1.js, et modifier PrixLot2.js de manière à pouvoir :

  • enchaîner plusieurs jeux consécutifs lors d'une même exécution du programme (à la fin de chaque jeu, il est demandé au joueur de préciser s'il veut s'arrêter ou rejouer)

  • limiter le nombre d'essais du joueur lors d'une partie (au début de chaque partie, le programme demandera le nombre maximum d'essais autorisés).

Exemple d'exécution du programme PrixLot2

P:\TW\TP05>node PrixLot2 
Le but est de chercher un prix entre 0 et 1000
1ère partie. Nombre maximum d'essais : 4
Tapez un prix : 678
Trop petit
Tapez un prix : 920
Trop grand
Tapez un prix : 860
Trop petit 
Tapez un prix : 910
Trop petit
PERDU ! Vous avez épuisé le nombre d'essais autorisés
Le prix était : 917
                                
Voulez-vous rejouer O/N ? o
2ème partie. Nombre maximm d'essais : 8
Tapez un prix : 678
Trop grand
Tapez un prix : 333
Trop grand
Tapez un prix : 300
Trop petit
Tapez un prix : 320
Trop petit
Tapez un prix : 324
BRAVO !
Vous avez gagné en 5 essais

Voulez-vous rejouer O/N ? n
P:\TW\TP05>

Exercice 3.3 : En jouant avec le programme précédent, essayer de trouver une stratégie systématique et efficace. Ecrire un programme PrixLot3.js qui fait jouer l'ordinateur à votre place suivant la tactique que vous venez de définir ; les deux rôles de meneur de jeu et de joueur sont donc à la charge du programme, le joueur "ignorant" évidemment le prix connu du meneur de jeu, mais "sachant" si son essai est plus grand ou plus petit que le prix.

Le programme PrixLot3 effectue 20 parties ; il affiche pour chaque partie le prix tiré au sort et le nombre d'essais successifs qui ont été nécessaires pour le trouver avec la tactique programmée.

Pouvez-vous prévoir, pour la tactique que vous avez choisie, l'ordre de grandeur des nombres d'essais ? Compléter le programme PrixLot3 en lui faisant calculer la moyenne des 20 nombres d'essais obtenus pour les 20 parties.

Exercice 4 : Valeur approchée de la racine carrée d'un nombre réel positif

On considère un nombre réel positif A ; on sait que la suite (un) n=0,1,2,... définie par la donnée d'un réel u0 positif et par la relation de récurrence un = (un-1 + A / un-1) * 0,5 (pour n > 0) converge vers la racine carrée de A . On suppose le nombre A compris entre 1 et 100, et on prend u0 = A / 2.

Pour obtenir une valeur approchée de racine carrée de A, on cherche le premier terme un tel que | un2 - A | < E-5 . Le nombre trouvé est une valeur approchée de racine carrée de A ( en effet | un2 - A | < E-5 implique que | un- rac(A) | < E-5 / ( un+ rac(A) où rac(A) correspond à la racine carrée de A).

a) Ecrivez un programme JavaScript Raca1.js qui permet

  1. de lire le nombre A,

  2. de calculer et d'afficher les approximations intermédiaires et la valeur approchée de la racine carrée de A définie ci-dessus.

Exemple de l'état de l'écran obtenu par exécution du programme Raca1 :

Entrer un nombre A entre 1 et 100: 19.23 
Approximations successives :
u0 = 9.615
u1 = 5.8075
u2 = 4.559367735686612
u3 = 4.388528900180239
u4 = 4.385203650605606 
Valeur approchée de la racine carrée  = 4.385202389856321

Indications pour écrire le programme :

  • définir une constante : const EPS = 1E-5;
  • utiliser une boucle tant que :
while (. . . . . . . >= EPS) {
. . . . . . . . . 
}

b) à partir du programme Raca1.js écrire un programme Raca2.js qui vérifie que le nombre introduit au clavier est bien un nombre positif supérieur à 1, et dans le cas contraire affiche un message d'erreur et redemande une nouvelle valeur à l'utilisateur.