This shows you the differences between two versions of the page.
alf:laboratoare:01 [2020/02/24 19:21] alexandru.radovici |
alf:laboratoare:01 [2022/03/06 16:20] (current) diana.ghindaoanu [Exercices] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ======= TP 1 - Introduction sur NodeJS ======= | + | ====== TP 1 - Structures de données ====== |
- | ====== Installation de NodeJS / éditeur de texte ====== | + | ===== Tableaux ===== |
+ | Un tableau (**array**) est une collection homogène qui stocke des valeurs avec le même type de données | ||
+ | * ils sont //statiques//: une fois initialisés, leur dimension ne peut pas être modifiée | ||
+ | * chaque élément est identifié par un entier unique appelé //index// | ||
+ | * ils doivent être déclarés avant l'utilisation | ||
+ | * l'initialisation fait référence au remplissage du tableau avec des éléments | ||
+ | <code javascript> | ||
+ | let values:string[]; | ||
+ | values = ["1","2","3","4"] | ||
+ | console.log(values[0]); //1 | ||
+ | console.log(values[1]); //2 | ||
+ | </code> | ||
- | ==== Éditeurs de texte ==== | + | * il peut être créé aussi à l'aide de l'objet Array, en donnant comme paramètre la taille ou une liste de valeurs. Comme peut-être vous le savez déjà d'autres langages de programmation, les listes peuvent être declarés aussi en utilisant des types de tableau générique (template, ''Array<T>'') |
+ | <code javascript> | ||
+ | let arr_names:number[] = new Array<number>(4) | ||
- | * **Visual Studio Code** [[https://code.visualstudio.com/]] - notre conseil | + | for(let i = 0;i<arr_names.length;i++) { |
- | * Sublime Text [[https://www.sublimetext.com/]] | + | arr_names[i] = i * 2 |
- | * Atom [[https://atom.io/]] | + | console.log(arr_names[i]) |
- | * Brackets [[http://brackets.io/]] | + | } |
- | ==== NodeJS ==== | + | var names:string[] = new Array<string>("Mary","Tom","Jack","Jill") |
- | * Naviguez vers [[http://www.nodejs.org]] | + | |
- | * Téléchargez NodeJS version 12 LTS pour votre système d'exploitation (Windows/Linux/Mac) | + | |
- | ====== Tutoriel NodeJS ====== | + | for(var i = 0;i<names.length;i++) { |
+ | console.log(names[i]) | ||
+ | } | ||
+ | </code> | ||
- | ==== Standard ==== | + | === Fonctions prédéfinies pour les tableaux === |
- | Afin de lancer plus d'erreurs qui vont vous aider à deboguer (debug) les programmes, il faut que tous les programmes que vous créez commencent par : | + | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length|list.length]]// - numéro d'éléments du tableau |
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf|list.indexOf (search, index)]]// - numéro de l'indice correspondant à la variable "search" | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf|list.lastIndexOf (search, index)]]// - indice pour la derniere apparition de la variable "search" | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push|list.push (element, ...)]]// - ajouter un element au tableau | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop|list.pop ()]]// - supprimer et retourner la valeur du dernier élément de la liste | ||
+ | * //[[https://developer.mozilla.org/en- US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice|list.splice (start, deleteCount, pushElement, ...)]]// - changer le contenu du tableau, en supprimant ou en remplaçant certains éléments | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map|list.map (functionToRun)]]// - créer un nouveau tableau contenant des éléments générés par la fonction appelée | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex|list.findIndex (functionToSearch)]]// - retourne l'indice du premier élément qui satisfait la fonction appelée | ||
+ | * //[[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter|list.filter (functionToFilter)]]// - nouveau tableau avec les éléments qui répondent à la condition incluse dans la fonction-paramètre | ||
+ | |||
+ | |||
+ | ===== String ===== | ||
+ | L'objet global **String** est un constructeur de chaînes de caractères. | ||
+ | Les littéraux de chaînes de caractères peuvent avoir l'une des formes suivantes : | ||
<code javascript> | <code javascript> | ||
- | "use strict"; | + | "text" |
+ | 'text' | ||
+ | "'text' in text" | ||
+ | 'It\'s a sunny day!' //character escaping | ||
</code> | </code> | ||
- | ===== Types de données en JavaScript ===== | + | === Fonctions prédéfinies pour les chaînes de caractères === |
- | * **Primitives** | + | * //str.length//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/length|FR]]) - la longueur d'une chaîne |
- | * Number | + | * //str.substring(start, end)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/substring|FR]]) - retourne le sous-string à partir de la position //start// jusqu'à la position //end// (le dernier paramètre est optionnel) |
- | * String | + | * //str.split(separator, limit)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/split|FR]]) - divise le string dans un array avec des éléments séparés par le //separator// |
- | * Boolean | + | * //separator// - un string avec les caractères après lesquelles on veut séparer le string original |
- | * Symbol | + | * //limit// - le nombre maximum de divisions (optionnel) |
- | * Null | + | * //str.toUpperCase()//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/toUpperCase|FR]]) - retourne un nouveau string avec toutes les lettres majuscules |
- | * Undefined | + | * //str.toLowerCase()//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/toLowerCase|FR]]) - retourne un nouveau string avec toutes les lettres minuscules |
- | * **Object** | + | * //str.indexOf(search, index)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/indexOf|FR]]) - retourne l'index de //search// |
+ | * //search// - l'élément cherché | ||
+ | * //index// - l'index à partir duquel on commence à chercher | ||
+ | * //str.lastIndexOf(search, index)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/lastIndexOf|FR]]) - la dernière apparition de //search// | ||
+ | * //str.trim()//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/trim|FR]]) - on supprime tous les espaces du début et de la fin du string | ||
+ | * //str.startsWith(search, index)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/startsWith|FR]]) - détermine si une chaîne commence par les caractères de //search// | ||
+ | * //str.endsWith(search, index)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/endsWith|FR]]) - détermine si une chaîne se termine par les caractères de //search// | ||
+ | * //str.replace(subStr, newSubStr)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace|EN]], [[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace|FR]]) - retourne un nouveau string avec //newSubStr// au lieu de //subStr// | ||
+ | * //str.charAt(index)//([[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt|EN]], [[https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/String/charAt|FR]]) - retourne le caractère qui se trouve a la position //index// | ||
- | ===== Affichage des données ===== | + | ===== Object ===== |
+ | Les objets representent la manière fondamentale dont on peut regrouper et transmettre les données. En TypeScript, nous les représentons via des //types d'objets//. | ||
+ | * Anonymes <code javascript> function imprimerForme(forme: { name: string; surface: number }) { | ||
+ | return "Surface rectangle: " + forme.surface; | ||
+ | }</code> | ||
+ | * Nommés à l'aide d'une interface <code javascript> interface Forme{ | ||
+ | name: string; | ||
+ | surface: number; | ||
+ | } | ||
- | La fonction //console.log()// est utilisée pour afficher sur l'écran les données reçues comme paramètres. On peut lui passer plusieurs arguments. | + | function imprimerForme(forme: Forme) { |
+ | return "Surface rectangle: " + forme.surface; | ||
+ | }</code> | ||
+ | * Nommés à l'aide d'un alias type <code javascript>type Forme = { | ||
+ | name: string; | ||
+ | surface: number; | ||
+ | }; | ||
- | <code javascript> | + | function greet(forme: Forme) { |
- | console.log(5); // => 5 | + | return "Surface rectangle: " + forme.surface; |
- | console.log("Hello World!"); // => Hello World! | + | }</code> |
- | </code> | + | |
+ | ==== Modificateurs de propriété ==== | ||
+ | Chaque propriété d'un type d'objet peut spécifier plusieurs choses: le type, si la propriété est facultative et si la propriété peut être écrite. | ||
+ | ===Propriétés Facultatives=== | ||
+ | La plupart du temps, nous nous retrouverons face à des objets qui pourraient avoir un ensemble de propriétés. Dans ces cas, nous pouvons marquer ces propriétés comme facultatives en ajoutant un point d'interrogation (?) a la fin de leurs noms. Si on a une propriété facultative, cela veut dire qu'au moment de l'utilisation de l'objet, elle peut etre définie ou pas, comme dans l'example suivant: <code javascript> interface PaintOptions { | ||
+ | shape: Shape; //obligatoire | ||
+ | xPos?: number; //facultatif | ||
+ | yPos?: number; //facultatif | ||
+ | } | ||
- | ===== Variables ===== | + | function paintShape(opts: PaintOptions) { |
+ | // ... | ||
+ | } | ||
- | Les variables sont utilisées pour stocker des données. JavaScript est typé dynamiquement comme la plupart des autres langages de script. (Tous les types de données peuvent être déclarés avec //var//; on n'a pas //int//, //float//, //boolean//...). Par exemple, une variable initialement associée à un nombre peut être réaffectée à une chaîne de caractères. | + | const shape = getShape(); |
+ | paintShape({ shape }); //valide | ||
+ | paintShape({ shape, xPos: 100 }); //valide | ||
+ | paintShape({ shape, yPos: 100 }); //valide | ||
+ | paintShape({ shape, xPos: 100, yPos: 100 }); //valide</code> | ||
+ | <note important> | ||
+ | La déclaration ''nom?: type'' représente en fait une matiere plus efficace de declarer les variables comme ''nom: type | null | undefined''. | ||
+ | |||
+ | **Par exemple:** | ||
<code javascript> | <code javascript> | ||
- | var x = 20; | + | let nom: string = null; // Incorrect, car la variable doit recevoir un string lors de l'assignation, et null n'est pas un string |
- | var y = x + 5; | + | |
- | console.log (x); // 20 | + | let nom?: string = null; // Correct, car la construction ?: signifie que nom peut etre soit string, soit null, soit undefined |
- | console.log (y); // 25 | + | |
</code> | </code> | ||
+ | </note> | ||
- | Le mot-clé **let** permet de déclarer des variables dont la portée est limitée à celle du bloc dans lequel elles sont déclarées. Le mot-clé **var** permet de définir une variable globale ou locale à une fonction (sans distinction des blocs utilisés dans la fonction). | ||
+ | **Attention!**. On peut aussi lire depuis les propriétés facultatives, mais TypeScript va réaliser //strictNullChecks// et il va nous avertir que la variable pourrait etre ''undefined''. | ||
<code javascript> | <code javascript> | ||
- | var i; | + | function paintShape(opts: PaintOptions) { |
- | for(i = 0; i < 2; i++) { | + | let xPos: number = opts.xPos; |
- | var a = 1; | + | // ^ = Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'.ts(2322) |
- | let b = 2; | + | let yPos: number = opts.yPos; |
- | console.log(i + a + b); | + | // ^ = Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'.ts(2322) |
} | } | ||
- | |||
- | /* Output: | ||
- | 3 | ||
- | 4 | ||
- | */ | ||
- | |||
- | console.log(i); //2 | ||
- | console.log(a); //1 | ||
- | console.log(b); //ReferenceError: b is not defined | ||
</code> | </code> | ||
- | + | Afin de gérer ce probleme, on peut utiliser [[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator|l'opérateur ternaire]]. | |
- | + | ||
- | ===== String ===== | + | |
- | + | ||
- | L'objet global **String** est un constructeur de chaînes de caractères. | + | |
- | Les littéraux de chaînes de caractères peuvent avoir l'une des formes suivantes : | + | |
<code javascript> | <code javascript> | ||
- | "text" | + | function paintShape(opts: PaintOptions) { |
- | 'text' | + | let xPos: number = opts.xPos === undefined ? 0 : opts.xPos; |
+ | let yPos: number = opts.yPos === undefined ? 0 : opts.yPos; | ||
+ | |||
+ | let xPos: number = opts.xPos ?? 0; // Si opts.xPos est null ou undefined, la variable recevra 0; sinon, l'expression évaluera le parametre de gauche | ||
+ | } | ||
</code> | </code> | ||
- | ===== Enchaînement des Strings (concatenation) ===== | + | ===Propriétés Readonly === |
- | + | Les propriétés peuvent également être marquées comme //readonly// pour TypeScript. Bien qu'il ne modifie aucun comportement lors de l'exécution, une propriété marquée comme //readonly// ne peut pas être écrite pendant la vérification de type. | |
- | L'opérateur **+** effectue une concaténation des chaînes de caractères si au moins l'un des opérandes est une chaîne. Ensuite, l'autre opérande est converti en chaîne. | + | |
- | | + | |
<code javascript> | <code javascript> | ||
- | console.log("Hello " + "World!"); //Hello World! | + | interface Forme { |
- | console.log("It's " + 2019); //It's 2019 | + | readonly name: string; |
- | </code> | + | } |
+ | function afficherInfo(obj: Forme) { | ||
+ | // We can read from 'obj.prop'. | ||
+ | console.log(`prop has the value '${obj.name}'.`); | ||
- | ===== Créer un nouveau projet en Node.js ===== | + | // But we can't re-assign it. |
+ | obj.name= "hello"; | ||
+ | // ERROR: Cannot assign to 'name' because it is a read-only property. | ||
+ | } | ||
+ | </code> | ||
- | <note warning> | + | L'utilisation du modificateur readonly n'implique pas nécessairement qu'une valeur est totalement immuable - ou en d'autres termes, que son contenu interne ne peut pas être modifié. Cela signifie simplement que la propriété elle-même ne peut pas être réécrite. |
- | Vous avez la possibilité soit d'utiliser l'interface graphique pour créer les directoires et les fichiers nécessaires, soit d'introduire les commandes suivantes dans **Node.js command prompt**! | + | <code javascript> |
- | </note> | + | interface Home { |
+ | readonly resident: { name: string; age: number }; | ||
+ | } | ||
- | Créer un directoire pour le projet: | + | function visitForBirthday(home: Home) { |
+ | // We can read and update properties from 'home.resident'. | ||
+ | console.log(`Happy birthday ${home.resident.name}!`); | ||
+ | home.resident.age++; | ||
+ | } | ||
- | <code bash> | + | function evict(home: Home) { |
- | mkdir folder_name #ex: mkdir Projet | + | // But we can't write to the 'resident' property itself on a 'Home'. |
+ | home.resident = { | ||
+ | // Error: Cannot assign to 'resident' because it is a read-only property. | ||
+ | name: "ALF student", | ||
+ | age: 42, | ||
+ | }; | ||
+ | } | ||
</code> | </code> | ||
+ | ====Extension des types ==== | ||
- | On accède au répertoire qu'on vient de créer en utilisant la commande //cd// (change directory) qui reçoit comme paramètre le chemin vers le directoire. Le chemin peut être: | + | Soit l'interface suivante et supposons qu'on veut créer une interface qui contienne les memes propriétés, mais aussi d'autres supplémentaires. Par conséquent, on va utiliser l'extension des types, pour ne pas redéclarer une nouvelle interface presqu'identique: |
- | * absolu - contient le directoire racine et tous les autres sous-directoires dans lesquels un fichier ou un directoire est contenu (ex: C:\Users\student\Desktop\Projet) | + | |
- | * relatif - commence à partir du directoire de travail donné (ex: Desktop\Projet) | + | |
- | <code bash> | + | <code javascript> |
- | cd path_to_folder #ex: cd Projet, cd Desktop/Projet | + | interface BasicAddress { |
+ | name?: string; | ||
+ | street: string; | ||
+ | city: string; | ||
+ | country: string; | ||
+ | postalCode: string; | ||
+ | } | ||
+ | |||
+ | interface AddressWithUnit extends BasicAddress { | ||
+ | unit: string; | ||
+ | } | ||
</code> | </code> | ||
+ | Ou bien, si on veut étendre 2 interfaces, on peut utiliser: | ||
+ | <code javascript> | ||
+ | interface Colorful { | ||
+ | color: string; | ||
+ | } | ||
+ | interface Circle { | ||
+ | radius: number; | ||
+ | } | ||
- | On doit créer un fichier nommé //package.json//. Pour ne pas saisir les données mannuellement, il est recommandé dutiliser le gestionnaire de paquets //npm//. | + | interface ColorfulCircle extends Colorful, Circle {} |
- | <code bash> | + | const cc: ColorfulCircle = { |
- | npm init | + | color: "red", |
+ | radius: 42, | ||
+ | }; | ||
</code> | </code> | ||
- | Après avoir introduit cette commande dans le terminal Node.js, il faudra fournir des informations sur le nouveau projet afin de remplir certains champs. Si vous n'etes pas sûr de ce qu'il faut écrire, vous pouvez tout simplement appuyer sur la touche //Enter// pour associer les valeurs par défaut. | ||
- | Pour installer des modules, on utilise //npm install//. Le drapeau **-****-save** les ajoutera automatiquement à votre package.json (pour une installation globale, on utilise **-g**): | + | ==== Intersection des types ==== |
+ | TypeScript fournit une autre construction appelée **type intersection** qui est principalement utilisée pour combiner des types d'objets existants. | ||
- | <code bash> | + | Un type d'intersection est défini à l'aide de l'opérateur ''&''. |
- | npm install lib_name --save | + | |
- | </code> | + | |
- | Pour exécuter le projet, on écrit la commande suivante (on doit être dans le même directoire que le fichier!): | + | <code javascript> |
+ | interface Colorful { | ||
+ | color: string; | ||
+ | } | ||
+ | interface Circle { | ||
+ | radius: number; | ||
+ | } | ||
- | <code bash> | + | type ColorfulCircle = Colorful & Circle; |
- | node file_name.js | + | function draw(circle: Colorful & Circle) { |
- | </code> | + | console.log(`Color was ${circle.color}`); |
+ | console.log(`Radius was ${circle.radius}`); | ||
+ | } | ||
- | Si on a besoin d'autres paramètres supplémentaires pour exécuter le programme, on va les écritre apres le nom du fichier, comme dans l'exemple suivant: | + | // okay |
- | + | draw({ color: "blue", radius: 42 }); | |
- | <code bash> | + | |
- | node file_name.js param1 param2 | + | |
</code> | </code> | ||
- | ===== Modules de NodeJS ====== | + | ==== Réunion des types ==== |
- | + | La réunion des types décrit une valeur qui peut recevoir l'un de plusieurs types. Nous utilisons la barre verticale ''|'' pour séparer chaque type, donc number| string| boolean est le type d'une valeur qui peut être un //number//, une //string// ou un //boolean//. | |
- | La signification des modules en NodeJS est la même que pour les bibliothèques JavaScript. Plus précisément, le module contient un ensemble de fonctions que vous allez inclure dans votre application. | + | |
- | Pour inclure un module dans le projet, il faut utiliser la fonction //require()//, accompagnée par le nom du module: | + | |
<code javascript> | <code javascript> | ||
- | var module_name = require('module_name'); | + | interface Bird { |
- | </code> | + | fly(): void; |
+ | layEggs(): void; | ||
+ | } | ||
- | Par exemple, pour fournir une interface facile à utiliser en appliquant des couleurs et des styles à la sortie de ligne de commande, on peut inclure le module //chalk// dans le projet. | + | interface Fish { |
+ | swim(): void; | ||
+ | layEggs(): void; | ||
+ | } | ||
- | <code javascript> | + | declare function getSmallPet(): Fish | Bird; |
- | var chalk = require('chalk'); | + | |
- | console.log(chalk.blue('Hello world!')); | + | |
- | </code> | + | |
- | ===== Écrire dans un fichier ===== | + | let pet = getSmallPet(); |
+ | pet.layEggs(); | ||
- | Pour écrire dans un fichier, on utilise le module //fs//, de la façon suivante: | + | // Only available in one of the two possible types |
+ | pet.swim(); | ||
+ | Property 'swim' does not exist on type 'Bird | Fish'. | ||
+ | Property 'swim' does not exist on type 'Bird'. | ||
+ | </code> | ||
+ | ===== Classes ===== | ||
+ | Dans la programmation orientée objet, une classe est un modèle de code de programme extensible pour créer des objets, fournissant des valeurs initiales pour l'état (variables) et des implémentations de comportement (fonctions ou méthodes). | ||
+ | En JavaScript, on peut créer des applications en utilisant cette approche basée sur les classes orientée objet. Dans TypeScript, on permet aux développeurs d'utiliser ces techniques maintenant et de les compiler en JavaScript qui fonctionne sur tous les principaux navigateurs et plates-formes, sans avoir à attendre la prochaine version de JavaScript. | ||
<code javascript> | <code javascript> | ||
- | var fs = require('fs'); | + | class Animal { |
+ | name: string; | ||
- | try { | + | constructor(message: string) { |
- | fs.writeFileSync('file_path', text_to_write, 'utf8'); //UTF-8 est l'encodage du texte | + | this.name= message; |
- | } catch(err) { | + | } |
- | console.error(err); | + | |
+ | printBreed() { | ||
+ | return "This animal is a " + this.name; | ||
+ | } | ||
} | } | ||
+ | |||
+ | let bear = new Greeter("bear"); | ||
</code> | </code> | ||
- | ===== Lire un fichier ===== | + | ==== Héritage ==== |
- | Pour lire un fichier, on utilise le meme module //fs//, mais comme dans l'exemple suivant: | + | Dans TypeScript, nous pouvons utiliser des modèles orientés objet courants. L'un des modèles les plus fondamentaux de la programmation basée sur les classes est de pouvoir étendre les classes existantes pour en créer de nouvelles à l'aide de l'héritage. |
<code javascript> | <code javascript> | ||
- | var fs = require('fs'); | + | class Animal { |
+ | name: string; | ||
+ | constructor(theName: string) { | ||
+ | this.name = theName; | ||
+ | } | ||
+ | move(distanceInMeters: number = 0) { | ||
+ | console.log(`${this.name} moved ${distanceInMeters}m.`); | ||
+ | } | ||
+ | } | ||
- | try { | + | class Snake extends Animal { |
- | var data = fs.readFileSync(file_path).toString(); | + | constructor(name: string) { |
- | console.log(data); //contenu du fichier (String) | + | super(name); |
- | } catch(err) { | + | } |
- | console.error(err); | + | move(distanceInMeters = 5) { |
+ | console.log("Slithering..."); | ||
+ | super.move(distanceInMeters); | ||
+ | } | ||
} | } | ||
- | </code> | ||
+ | class Horse extends Animal { | ||
+ | constructor(name: string) { | ||
+ | super(name); | ||
+ | } | ||
+ | move(distanceInMeters = 45) { | ||
+ | console.log("Galloping..."); | ||
+ | super.move(distanceInMeters); | ||
+ | } | ||
+ | } | ||
- | ===== Instructions conditionnelles ===== | + | let sam = new Snake("Sammy the Python"); |
+ | let tom: Animal = new Horse("Tommy the Palomino"); | ||
- | En JavaScript, nous avons les instructions conditionnelles suivantes: | + | sam.move(); |
- | * **if** - pour spécifier un bloc de code à exécuter, si la condition est vraie | + | tom.move(34); |
- | * **else** - pour spécifier un bloc de code à exécuter, si la même condition qua est fausse | + | </code> |
- | * **else if** - pour spécifier une nouvelle condition à tester, si la première condition est fausse | + | |
- | * **switch** - pour spécifier plusieurs blocs de code alternatives à exécuter | + | |
- | === If === | + | Chaque classe dérivée qui contient une fonction **constructor** doit appeler **super()** qui exécutera le constructeur de la classe de base. De plus, avant d’accéder à une propriété à ce sujet dans un corps de constructeur, nous devons appeler super(). C'est une règle importante que TypeScript appliquera. |
+ | |||
+ | L'exemple montre également comment remplacer les méthodes de la classe de base par des méthodes spécialisées pour la sous-classe. Ici, Snake et Horse créent une méthode de déplacement qui remplace le déplacement d'Animal, lui donnant des fonctionnalités spécifiques à chaque classe. Notez que même si tom est déclaré comme un animal, puisque sa valeur est un cheval, appeler tom.move (34) appellera la méthode de substitution dans Horse. | ||
+ | |||
+ | ==== Modificateurs ==== | ||
+ | Par défaut, tous les membres d'une classe dans TypeScript sont de type ''public''. Tous les membres publics sont //accessibles// n'importe où sans aucune restriction. | ||
+ | Le modificateur d'accès ''private'' garantit que les membres de la classe ne sont visibles que pour cette classe et //ne sont pas accessibles en dehors de la classe ou ils ont été créés//. | ||
+ | Le modificateur d'accès ''protected'' est similaire au modificateur d'accès privé, sauf que les membres protégés sont //accessibles à l'aide de leurs classes dérivantes//. | ||
<code javascript> | <code javascript> | ||
- | var x = 1; | ||
- | if(x === 1) { | + | class Employee { |
- | console.log(x); //l'instruction s'execute | + | public empName: string; |
+ | private empEmail: string; | ||
+ | protected empCode: number; | ||
+ | |||
+ | constructor(name: string, email: string, code: number){ | ||
+ | this.empName = name; | ||
+ | this.empEmail = email; | ||
+ | this.empCode = code; | ||
+ | } | ||
} | } | ||
- | if(x > 3) { | + | class SalesEmployee extends Employee{ |
- | console.log(x + 3); //l'instruction ne s'execute pas | + | private department: string; |
+ | |||
+ | constructor(name: string, email: string, code: number, department: string) { | ||
+ | super(name, email, code); | ||
+ | this.department = department; | ||
+ | } | ||
+ | printProperties() { | ||
+ | console.log(this.empName + " " + this.empEmail + " " + this.empCode); | ||
+ | // ^ Property 'empEmail' is private and only accessible within class 'Employee'.ts(2341) | ||
+ | } | ||
} | } | ||
- | </code> | ||
- | === If Else === | + | let empObj = new SalesEmployee("John Smith", "john@gmail.com", 123, "Sales"); |
+ | console.log(empObj); | ||
+ | empObj.empEmail; // Property 'empEmail' is private and only accessible within class 'Employee'.ts(2341) | ||
+ | empObj.empCode; // Property 'empCode' is protected and only accessible within class 'Employee' and its subclasses.ts(2445) | ||
+ | </code> | ||
+ | Une autre forme de créer le constructeur est à l'aide des paramètres de la classe: | ||
<code javascript> | <code javascript> | ||
- | var x = 5; | + | constructor (public n: number, private s: number) {} |
- | if(x < 3) { | + | /* identique à */ |
- | console.log(x + 3); | + | |
- | } | + | constructor (n: number, s: number) { |
- | else { | + | this. n = n; |
- | console.log(x + 1); //seulement cette instruction s'execute | + | this.s = s; |
} | } | ||
</code> | </code> | ||
- | === If Else if === | + | ==== Accesseurs ==== |
+ | TypeScript prend en charge les getters / setters comme moyen d'intercepter les accès à un membre d'un objet. Cela vous donne un moyen d'avoir un contrôle plus fin sur la façon dont un membre est accédé sur chaque objet. | ||
<code javascript> | <code javascript> | ||
- | var x = 2; | + | class Employee { |
+ | private _fullName: string = ""; | ||
- | if(x < 3) { | + | get fullName(): string { |
- | console.log(x + 3); //seulement cette instruction s'execute | + | return this._fullName; |
+ | } | ||
+ | |||
+ | set fullName(newName: string) { | ||
+ | this._fullName = newName; | ||
+ | } | ||
} | } | ||
- | else if (x > 4){ | + | |
- | console.log(x + 1); | + | let employee = new Employee(); |
+ | employee.fullName = "Bob Smith"; | ||
+ | |||
+ | if (employee.fullName) { | ||
+ | console.log(employee.fullName); | ||
} | } | ||
</code> | </code> | ||
- | === Switch === | + | ==== Propriétés statiques ==== |
+ | Jusqu'à présent, nous n'avons parlé que des membres //d'instance// de la classe, ceux qui apparaissent sur l'objet lorsqu'il est instancié. Nous pouvons également créer des membres statiques d'une classe, ceux qui sont visibles sur la classe elle-même plutôt que sur les instances. Dans cet exemple, nous utilisons ''static'' sur //origin//, car il s'agit d'une valeur générale pour toutes les grilles. Chaque instance accède à cette valeur en ajoutant le nom de la classe. De même pour ajouter //this.// devant les accès aux instances, nous ajoutons ici //Grid.// devant les accès statiques. | ||
<code javascript> | <code javascript> | ||
- | var x = 2; | + | class Grid { |
- | + | static origin = { x: 0, y: 0 }; | |
- | switch(x) { | + | |
- | case 1: | + | calculateDistanceFromOrigin(point: { x: number; y: number }) { |
- | console.log(x + 1); | + | let xDist = point.x - Grid.origin.x; |
- | break; | + | let yDist = point.y - Grid.origin.y; |
- | case 2: | + | return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale; |
- | console.log(x + 2); //seulement cette instruction s'execute | + | } |
- | break; | + | |
- | case 3: | + | constructor(public scale: number) {} |
- | console.log(x + 3); | + | } |
- | break; | + | |
- | default: | + | let grid1 = new Grid(1.0); // 1x scale |
- | console.log(x); //instruction qui s'execute si x n'est pas egal a 1, 2 ou 3 | + | let grid2 = new Grid(5.0); // 5x scale |
- | } | + | |
+ | console.log(grid1.calculateDistanceFromOrigin({ x: 10, y: 10 })); | ||
+ | console.log(grid2.calculateDistanceFromOrigin({ x: 10, y: 10 })); | ||
</code> | </code> | ||
+ | ==== TypeScript Class vs. Interface ==== | ||
+ | Les classes et les interfaces sont des structures puissantes qui facilitent non seulement la programmation orientée objet, mais également la vérification de type dans TypeScript. Une classe est un plan à partir duquel nous pouvons créer des objets qui partagent la même configuration - propriétés et méthodes. Une interface est un groupe de propriétés et de méthodes associées qui décrivent un objet, mais ne fournit ni implémentation ni initialisation pour eux. | ||
- | ===== Boucles ===== | + | ===== Fonctions ===== |
+ | Les fonctions sont sont fondamentales toute application en JavaScript. Ils vous permettent de créer des couches d’abstraction, d’imiter des classes, de masquer des informations et de modules. Dans TypeScript, bien qu'il existe des classes, des espaces de noms et des modules, les fonctions jouent toujours le rôle clé dans la description de la façon de faire les choses. | ||
- | Les boucles peuvent exécuter un bloc de code plusieurs fois. | + | * Fonctions nommées <code javascript>function add(x: number, y: number): number { |
+ | return x + y; | ||
+ | }</code> | ||
+ | * Fonctions anonymes <code javascript>let myAdd: (x: number, y: number) => number = function ( | ||
+ | x: number, | ||
+ | y: number | ||
+ | ): number { | ||
+ | return x + y; | ||
+ | }; </code> | ||
- | === For === | + | ===== Arguments de la ligne de commande ===== |
- | La boucle //for// parcourt un bloc de code un certain nombre de fois. | + | La propriété **process.argv** renvoie un tableau contenant les arguments de la ligne de commande transmis lors du lancement du processus Node.js. |
+ | Le premier élément sera process.execPath (le chemin d'executable //node//). | ||
+ | Le deuxième élément sera le chemin vers le fichier JavaScript en cours d'exécution. | ||
+ | Les autres éléments seront des arguments de ligne de commande supplémentaires. | ||
+ | |||
+ | |||
+ | Lancement du processus Node.js pour le fichier //process.js// : | ||
+ | <code bash> | ||
+ | $ node process.js one 2 three | ||
+ | </code> | ||
<code javascript> | <code javascript> | ||
- | var x = 10; | + | //process.js |
- | var sum = 0; | + | |
- | for(let i = 1; i <= x; i++) { | + | for(let argumentIndex:number = 0; argumentIndex < process.argv.length; argumentIndex++) { |
- | sum += i; | + | console.log(argumentIndex + ": " + process.argv[argumentIndex]); |
} | } | ||
- | console.log(sum); //55 | + | /* Output: |
+ | 0: C:\Program Files\nodejs\node.exe | ||
+ | 1: C:\Users\student\Desktop\process.js | ||
+ | 2: one | ||
+ | 3: 2 | ||
+ | 4: three | ||
+ | */ | ||
</code> | </code> | ||
- | === While === | + | ===== Fonctions parseInt et parseFloat ===== |
- | La boucle //while// parcourt un bloc de code tant qu'une condition spécifiée est vraie. | + | === parseInt === |
+ | |||
+ | La fonction //parseInt()// analyse une chaîne de caractère fournie en argument et renvoie un entier exprimé dans une base donnée. | ||
<code javascript> | <code javascript> | ||
- | var x = 1; | + | let string_var: string = "12"; |
- | var sum = 0; | + | let base: number = 10; |
+ | let number_value: number = parseInt(string_var, base); | ||
- | while(x <= 10) { | + | console.log(number_value); //12 |
- | sum += x; | + | </code> |
- | x++; | + | |
- | } | + | |
- | console.log(sum); //55 | + | * string_var - La valeur qu'on souhaite analyser et convertir. Si l'argument string n'est pas une chaîne de caractères, elle sera convertie en une chaîne. Les blancs contenus au début de l'argument sont ignorés. |
+ | * base - Un entier compris entre 2 et 36 qui représente la base utilisée pour la valeur représentée dans la chaîne. La base utilisée en général est la base décimale (valeur 10 pour ce paramètre). | ||
+ | |||
+ | |||
+ | === parseFloat === | ||
+ | |||
+ | La fonction //parseFloat()// permet de transformer une chaîne de caractères en un nombre réel. | ||
+ | |||
+ | <code javascript> | ||
+ | let string_var: string = "15.35"; | ||
+ | let number_value: number = parseFloat(string_var); | ||
+ | |||
+ | console.log(number_value); //15.35 | ||
</code> | </code> | ||
+ | * string - Une chaîne de caractères qui contient la valeur qu'on souhaite analyser et transformer dans un nombre flottant. | ||
- | ===== Oprateurs ===== | ||
- | ^ Operateur ^ Description ^ Example ^ | + | ===== Exercices ===== |
- | | + | Plus | x + y | | + | |
- | | - | Moins | x - y | | + | |
- | | * | Multiplication | x * y | | + | |
- | | / | Division | x / y | | + | |
- | | % | Reste de la division | x % y | | + | |
- | | == | Valeur d'égalité | x == y | | + | |
- | | === | Égalité de la valeur et du type | x === y | | + | |
- | | != | Valeur différente | x != y | | + | |
- | | !== | Différence de la valeur ou du type | x !== y | | + | |
- | | < | Moins grand | x < y | | + | |
- | | <= | Moins grand ou égal | x <= y | | + | |
- | | > | Plus grand | x > y | | + | |
- | | >= | Plus grand ou égal | x >= y | | + | |
- | | ! | Pas | !x | | + | |
- | | && | Et | x && y | | + | |
- | | %%||%% | Ou | x %%||%% y | | + | |
- | | & | AND | x & y | | + | |
- | | %%|%% | OR | x %%|%% y | | + | |
- | | ~ | NOT | x ~ y | | + | |
- | | %%^%% | XOR | x %%^%% y | | + | |
- | | >> | Right Shift | x >> y | | + | |
- | | << | Left Shift | x << y | | + | |
+ | - Créez un programme et exécutez-le avec des paramètres dans la ligne de commande. Sauvegardez la liste des parametres dans une variable. Affichez : (**1p**) | ||
+ | - la liste des paramètres avec //console.log// | ||
+ | - le nombre de paramètres | ||
+ | - les paramètres avec un //for//(à votre choix) | ||
+ | - Faites un programme qui contient une fonction //power// qui reçoit deux nombres comme paramètres, qui calcule la puissance et qui : (**1p**) | ||
+ | - affiche le résultat | ||
+ | - retourne le résultat | ||
+ | - stocke le résultat dans une variable et l'affiche | ||
+ | - A l'aide des interfaces, créez un nouveau type de données nommé Employé, qui contienne les champs suivants: //nom//, //prénom//, //département//, //expérience// (numéro) (**2p**) | ||
+ | - Créez un objet de type Employée qui recoit ses paramètres de la ligne de commande (''node index.js NomEmp PrenomEmp ALF 3'') | ||
+ | - Affichez chaque attribut de l'objet | ||
+ | - Faites un array avec 3 objets de type //Employee// | ||
+ | - Affichez l'étudiant avec la plus grande expérience | ||
+ | - Affichez la moyenne géométrique des années d'expérience de tous les employés | ||
+ | - Affichez la personne avec le prénom le plus longue | ||
+ | - Affichez tous les objets en ordre alphabétique apres le nom de famille | ||
+ | - Créez une classe Employé ayant les memes propriétés définies pour l'interface de l'exercice précedent (**1.5p**) | ||
+ | - Créez une sous-classe Manager, dérivée de la classe Employé, qui contient un champ supplémentaire //noSubordonnés// (number) | ||
+ | - Créez un objet de type Manager | ||
+ | - Créez une fonction qui recoit comme paramètre un string (nom d'une propriété) et qui vérifie si l'objet de type Manager a la propriété indiquée | ||
+ | - Écrivez un programme qui retourne un tableaux avec les sous-strings d'un string donnée. (ex: ['c', 'co', 'cod', 'o', 'od', 'd'] pour le string //cod//) (**1p**) | ||
+ | - Soit un objet de type Manager. Ecrivez un programme pour le convertir dans une liste de paires [key, value]. Par example: (**1.5p**)<code javascript>let newManager = new Manager("LastName", "FirstName", "Departement", 10, 30); | ||
+ | let keyValueList: (string|number)[][]; | ||
+ | /* Here goes your code */ | ||
+ | console.log(keyValueList); // [["nom", "LastName"], ["prenom", "FirstName"], ["department", "Departement"], ["experience", 10], ["noSubordonnes", 30]]</code> | ||
+ | - Soit le code suivant. Définissez le type Person et apportez les modifications nécessaires de sorte que le programme affiche la liste des objets de type Person (**1.5p**) <code javascript>interface User { | ||
+ | name: string; | ||
+ | age: number; | ||
+ | occupation: string; | ||
+ | } | ||
- | ===== Excercices ===== | + | interface Admin { |
+ | name: string; | ||
+ | age: number; | ||
+ | role: string; | ||
+ | } | ||
- | - Installez Node JS 12 et un éditeur de texte (**Visual Studio Code**, Sublime Text, Atom, Brackets). (**1p**) | + | export type Person = unknown; /* TODO: Definissez ici le type */ |
- | - Faites un nouveau projet en Node JS qui s'appelle //printname//. | + | |
- | - Faites un nouveau directoire //printname//. (**0.3p**) | + | |
- | - Dans le nouveau directoire, créez un fichier //index.js// (**0.3p**) | + | |
- | - Entrez dans le directoire et utilisez la commande //npm init//. (**0.4p**) | + | |
- | - Ecrivez un programme qui affiche sur l'écran votre nom et prénom, en utilisant l'opération de concaténation. (**0.5p**) | + | |
- | - Faites un nouveau projet qui s'appelle //systeminfo//. Inspectez la documentation du module [[https://nodejs.org/api/os.html|os]] et utilisez-le pour afficher les données suivantes (//Attention! L'installation du module n'est pas nécessaire, il suffit d'importer le module dans le projet//): | + | |
- | - l'endianité du cpu (endianness of the CPU, exemples: 'BE' , 'LE') (**0.3p**) | + | |
- | - le repertoire de base pour l'utilisateur actuel(home directory) (**0.3p**) | + | |
- | - la mémoire disponible en MB (1KB = 1024B, 1MB = 1024KB) (**0.4p**) | + | |
- | - Déclarez une variable pour la mémoire en kB, une pour la mémoire en MB (nombres entières), une pour le repertoire de base et une avec l'endianité du processeur. Ajoutez ces variables dans un string, avec des espaces entre eux. Affichez le string sur l'écran. (**1p**) | + | |
- | - Ecrivez dans le fichier //os.info// toutes les informations de l'exercice précédent. (**0.5p**) | + | |
- | - Installez le module //chalk//, en utilisant //npm//. Le module doit être ajouté automatiquement en //package.json//. (**0.5p**) | + | |
- | - Affichez toutes les variables de l'exercice 4 avec des couleurs différentes, en utilisant le module chalk. (**0.5p**) | + | |
- | - Stockez dans une variabe le nombre de secondes écoulées depuis le temps de démarrage du système (uptime). | + | |
- | - Affichez sur l’écran : "Your system has been running for: " + le nombre de secondes. (**0.5p**) | + | |
- | - Si le nombre est paire, affichez sur l'écran "The system has been running for an even number of seconds". Si le nombre est impaire, affichez "The system has been running for an odd number of seconds". (**0.5p**) | + | |
- | - Faites un projet qui s'appelle //math//. En utilisant la boucle //for//, affichez : | + | |
- | - tous les nombres entres 1 - 300 (**0.4p**) | + | |
- | - les mêmes nombres en ordre inverse (**0.4p**) | + | |
- | - tous les nombres divisibles par 9 (**0.4p**) | + | |
- | - tous les nombres divisibles par 3 et 11 (**0.4p**) | + | |
- | - tous les nombres divisibles par 5 ou 6 (**0.4p**) | + | |
- | - Stockez un nombre quelconque dans une variable. Utilisez la boucle //while// pour compter ses diviseurs. Affichez sur l’écran : | + | |
- | - "I chose the number x which has y divisors", où x représente la valeur du numéro que vous avez choisi et y le numéro de ses diviseurs (**0.5p**) | + | |
- | - Si le nombre est premier. (**0.5p**) | + | |
- | - **Bonus:** Utilisez le module //cowsay// pour afficher les spécifications de l'exercice 5. (**1p**) | + | |
- | ==== Solutions ==== | + | export const persons: User[] /* TODO: Modifiez en Person[] */ = [ |
+ | { | ||
+ | name: 'John Doe', | ||
+ | age: 25, | ||
+ | occupation: 'Chimney sweep' | ||
+ | }, | ||
+ | { | ||
+ | name: 'Jane Doe', | ||
+ | age: 32, | ||
+ | role: 'Administrator' | ||
+ | } | ||
+ | ]; | ||
- | [[https://github.com/UPB-FILS/alf/tree/master/TP/TP1|Solutions]] | + | export function logPerson(user: User) { /* TODO: Modifiez pour afficher la liste des objets Person */ |
+ | console.log(` - ${user.name}, ${user.age}`); | ||
+ | } | ||
+ | |||
+ | persons.forEach(logPerson);</code> | ||
+ | - On dit qu'une phrase est //pangram// si elle utilise toutes les lettres d'un alphabet donné. En utilisant la classe ci-dessous, définissez les éléments manquants afin de vérifier si une phrase choisie par vous est //pangram//. (**1.5p**) <code javascript>class Pangram { | ||
+ | private alphabet: string = 'abcdefghijklmnopqrstuvwxyz'; | ||
+ | |||
+ | constructor(private phrase: string) { | ||
+ | /* TODO */ | ||
+ | } | ||
+ | |||
+ | isPangram(): boolean { | ||
+ | /* TODO */ | ||
+ | return true; | ||
+ | } | ||
+ | }</code> | ||