Cours JavaScript et TypeScript · Module 1: Bases de JavaScript
Conversion de type et opérations sur les types
Dans cette leçon8
À Jurassic Park, les scientifiques ont souvent besoin de transformer des données d'une forme à une autre - traduire des séquences d'ADN en attributs de dinosaures, convertir des mesures entre différents systèmes ou analyser le comportement des animaux. De même en JavaScript, la conversion de type et les opérations sur les types de données sont des compétences fondamentales qui permettent de manipuler efficacement les données.
Conversion de type implicite (Type Coercion)
JavaScript est typé dynamiquement (ce sont les valeurs qui ont un type, pas les variables) et faiblement typé : quand une opération l'exige, il convertit lui-même les valeurs dans un autre type. C'est comme les systèmes adaptatifs automatiques de Jurassic Park qui s'ajustent aux conditions changeantes - parfois pratique, mais parfois surprenant.
Conversion dans les opérations arithmétiques
Lorsque JavaScript effectue des opérations arithmétiques, il essaie de convertir automatiquement les valeurs en nombres :
1// String + Number -> String (concaténation)
2"Velociraptor " + 3; // "Velociraptor 3"
3
4// String - Number -> Number
5"50" - 10; // 40 (la chaîne "50" est convertie en nombre)
6
7// String * Number -> Number
8"5" * 4; // 20 (la chaîne "5" est convertie en nombre)
9
10// String / Number -> Number
11"20" / 5; // 4 (la chaîne "20" est convertie en nombre)Remarque le cas particulier de l'opérateur +, qui pour les chaînes agit comme un opérateur de concaténation (jonction), et non d'addition. C'est comme observer que les velociraptors chassent toujours en meute - une connaissance qui peut te sauver la vie !
Conversion dans les opérations de comparaison
Lorsqu'on compare des valeurs de types différents avec l'opérateur == (égalité faible), JavaScript essaie de les convertir vers un type commun :
1// Number == String
25 == "5"; // true (la chaîne "5" est convertie en nombre 5)
3
4// Boolean == Number
5true == 1; // true (true est converti en 1)
6false == 0; // true (false est converti en 0)
7
8// null == undefined
9null == undefined; // true (cas particulier dans la spécification)
10
11// Object == Primitive
12[1] == 1; // true ([1] est converti en "1", puis en 1)Un tel comportement ressemble aux observations « intuitives » dans le parc - « Cet enclos a l'air identique à celui-là » - ce qui peut être trompeur si tu ne connais pas les détails.
Conversion dans les opérations logiques
Les opérateurs logiques &&, || et ! peuvent travailler avec des valeurs de tout type, en les convertissant implicitement en booléen :
1// L'opérateur ! (négation) convertit une valeur en booléen et la nie
2!0; // true (0 est converti en false, puis nié)
3!"Dino"; // false ("Dino" est converti en true, puis nié)
4
5// Les opérateurs && et || peuvent renvoyer les valeurs originales, pas seulement des booléens
6"T-Rex" && "Raptor"; // "Raptor" (si le premier opérande est truthy, renvoie le second)
70 || "Backup"; // "Backup" (si le premier opérande est falsy, renvoie le second)Cette logique est comme le protocole du parc : « Si la clôture fonctionne ET qu'elle est assez haute, le dinosaure ne s'échappera pas » - les deux conditions doivent être remplies pour que l'instruction entière soit vraie.
Conversion de type explicite
Pour éviter les résultats inattendus de la conversion implicite, il est souvent préférable de convertir explicitement les valeurs vers le type souhaité. C'est comme les protocoles de laboratoire précis de Jurassic Park - des procédures exactement définies donnant des résultats prévisibles.
Conversion en chaîne
1// Méthode n°1 : la fonction String()
2String(42); // "42"
3String(true); // "true"
4String(null); // "null"
5String(undefined); // "undefined"
6String({ name: "T-Rex" }); // "[object Object]"
7String([1, 2, 3]); // "1,2,3"
8
9// Méthode n°2 : la méthode toString()
10(42).toString(); // "42"
11true.toString(); // "true"
12[1, 2, 3].toString(); // "1,2,3"
13// null.toString(); // Erreur ! Null et undefined n'ont pas la méthode toString()
14
15// Méthode n°3 : concaténation avec une chaîne vide
1642 + ""; // "42"
17true + ""; // "true"
18null + ""; // "null"Conversion en nombre
1// Méthode n°1 : la fonction Number()
2Number("42"); // 42
3Number("42px"); // NaN (impossible de convertir toute la chaîne en nombre)
4Number(true); // 1
5Number(false); // 0
6Number(null); // 0
7Number(undefined); // NaN
8Number([1]); // 1 (un tableau à un seul élément est converti en son élément)
9Number([1, 2]); // NaN (un tableau à plusieurs éléments ne peut pas être converti)
10
11// Méthode n°2 : les fonctions parseInt() et parseFloat()
12parseInt("42"); // 42
13parseInt("42px"); // 42 (convertit jusqu'à rencontrer un caractère invalide)
14parseInt("3.14"); // 3 (convertit seulement la partie entière)
15parseFloat("3.14"); // 3.14 (convertit la partie à virgule flottante)
16
17// Méthode n°3 : les opérateurs unaires + et -
18+"42"; // 42
19-"42"; // -42
20+true; // 1Conversion en booléen
1// Méthode n°1 : la fonction Boolean()
2Boolean(42); // true
3Boolean(0); // false
4Boolean(""); // false
5Boolean("text"); // true
6Boolean(null); // false
7Boolean(undefined); // false
8Boolean({}); // true (tout objet est truthy)
9
10// Méthode n°2 : la double négation !!
11!!42; // true
12!!0; // false
13!!"text"; // true
14!!null; // falseTableaux de conversion
Les tableaux suivants sont comme les fiches génétiques des dinosaures du parc - ils montrent exactement ce qui se passe lors de la conversion entre différents types.
Conversion en chaîne
| Type d'entrée | Exemple d'entrée | Résultat de la conversion en chaîne |
|---|---|---|
| Number | 42 | "42" |
| Boolean | true | "true" |
| null | null | "null" |
| undefined | undefined | "undefined" |
| Array | [1, 2, 3] | "1,2,3" |
| Object | {name: "Rex"} | "[object Object]" |
| Function | function(){} | "function(){}" |
Conversion en nombre
| Type d'entrée | Exemple d'entrée | Résultat de la conversion en nombre |
|---|---|---|
| String | "42" | 42 |
| String | " 42 " | 42 (les espaces sont retirés) |
| String | "42px" | NaN |
| String | "" | 0 (chaîne vide) |
| Boolean | true | 1 |
| Boolean | false | 0 |
| null | null | 0 |
| undefined | undefined | NaN |
| Array | [] | 0 (tableau vide) |
| Array | [5] | 5 (tableau à un élément) |
| Array | [1, 2] | NaN (plusieurs éléments) |
| Object | {} | NaN |
Conversion en booléen
| Type d'entrée | Exemple d'entrée | Résultat de la conversion en booléen |
|---|---|---|
| Number | 42 | true |
| Number | 0 | false |
| Number | NaN | false |
| String | "text" | true |
| String | "" | false |
| null | null | false |
| undefined | undefined | false |
| Object | {} (n'importe) | true |
| Array | [] (n'importe) | true |
Opérations sur les types de données
Examinons maintenant les opérations détaillées sur les types de données individuels. C'est comme des procédures spécialisées pour différentes espèces de dinosaures.
Opérations sur les chaînes
Les chaînes en JavaScript offrent un riche ensemble de méthodes pour manipuler du texte :
1const parkName = "Jurassic Park";
2
3// Longueur d'une chaîne
4parkName.length; // 13
5
6// Accéder aux caractères individuels
7parkName[0]; // "J"
8parkName.charAt(0); // "J" (méthode alternative)
9
10// Rechercher des sous-chaînes
11parkName.indexOf("Park"); // 9 (indice où "Park" commence)
12parkName.startsWith("Jur"); // true
13parkName.endsWith("Park"); // true
14parkName.includes("assic"); // true
15
16// Changer la casse
17parkName.toUpperCase(); // "JURASSIC PARK"
18parkName.toLowerCase(); // "jurassic park"
19
20// Extraire des fragments
21parkName.substring(0, 8); // "Jurassic"
22parkName.slice(-4); // "Park" (compte depuis la fin)
23
24// Remplacer des fragments
25parkName.replace("Jurassic", "Dinosaur"); // "Dinosaur Park"
26
27// Diviser une chaîne en tableau
28parkName.split(" "); // ["Jurassic", "Park"]
29
30// Retirer les espaces
31" Danger Zone ".trim(); // "Danger Zone"
32
33// Joindre des chaînes
34"Welcome".concat(" to ", parkName); // "Welcome to Jurassic Park"
35
36// Répéter une chaîne
37"Roar! ".repeat(3); // "Roar! Roar! Roar! "Opérations sur les nombres
JavaScript offre de nombreuses possibilités pour travailler avec les nombres, à la fois directement sur les valeurs et via l'objet Math :
1// Opérations arithmétiques de base
25 + 3; // 8 (addition)
35 - 3; // 2 (soustraction)
45 * 3; // 15 (multiplication)
55 / 3; // 1.6666666666666667 (division)
65 % 3; // 2 (modulo - reste de la division)
75 ** 3; // 125 (exponentiation - 5 puissance 3)
8
9// Incrémentation et décrémentation
10let dinoCount = 5;
11dinoCount++; // dinoCount vaut maintenant 6
12dinoCount--; // dinoCount revient à 5
13
14// Opérateurs d'affectation et d'opération
15dinoCount += 3; // Identique à : dinoCount = dinoCount + 3
16dinoCount *= 2; // Identique à : dinoCount = dinoCount * 2
17
18// L'objet Math pour les opérations avancées
19Math.abs(-5); // 5 (valeur absolue)
20Math.round(4.7); // 5 (arrondi à l'entier le plus proche)
21Math.ceil(4.1); // 5 (arrondi au supérieur)
22Math.floor(4.9); // 4 (arrondi à l'inférieur)
23Math.max(3, 7, 2, 4); // 7 (trouver le maximum)
24Math.min(3, 7, 2, 4); // 2 (trouver le minimum)
25Math.pow(2, 3); // 8 (exponentiation - 2 puissance 3)
26Math.sqrt(16); // 4 (racine carrée)
27Math.sin(0); // 0 (sinus)
28Math.cos(0); // 1 (cosinus)
29Math.random(); // Nombre aléatoire de 0 (inclus) à 1 (exclus)
30
31// Générer un nombre aléatoire dans une plage
32function getRandom(min, max) {
33 return Math.floor(Math.random() * (max - min + 1)) + min;
34}
35getRandom(1, 10); // Nombre aléatoire de 1 à 10
36
37// Formater des nombres
38const height = 5.678934;
39height.toFixed(2); // "5.68" (deux décimales, renvoie une chaîne)
40height.toPrecision(3); // "5.68" (trois chiffres significatifs, renvoie une chaîne)
41height.toString(2); // "101.1010110111001110100111100101111000100100011110001" (représentation binaire)
42(1234567).toLocaleString(); // "1,234,567" (formatage avec séparateurs, dépend de la locale)Opérations booléennes
Bien que le type booléen n'ait que deux valeurs possibles, il existe de nombreuses opérations logiques :
1// Opérateurs de comparaison
25 > 3; // true (supérieur à)
35 >= 5; // true (supérieur ou égal)
43 < 5; // true (inférieur à)
53 <= 3; // true (inférieur ou égal)
65 == "5"; // true (égalité faible - les types différents sont convertis)
75 === "5"; // false (égalité stricte - les types doivent correspondre)
85 != "6"; // true (inégalité faible)
95 !== "5"; // true (inégalité stricte)
10
11// Opérateurs logiques
12true && true; // true (ET logique - les deux conditions doivent être vraies)
13true && false; // false
14true || false; // true (OU logique - au moins une condition doit être vraie)
15false || false; // false
16!true; // false (NON logique - négation)
17!false; // true
18
19// Conditions complexes
20const isSafe = fenceActive && powerLevel > 5000 && !stormApproaching;
21const needsEvacuation = alarmTriggered || dinoEscaped || stormStrength > 8;Opérations sur null et undefined
Malgré les possibilités limitées d'opérations directes sur null et undefined, il existe des modèles utiles pour travailler avec eux :
1// L'opérateur || pour les valeurs par défaut (attention : il remplace aussi 0 et la chaîne vide)
2const visitorName = userName || "Guest"; // Utilise userName s'il existe, sinon "Guest"
3
4// Opérateur de coalescence des nuls (??) - disponible dans les versions récentes de JS
5const count = dinoCount ?? 0; // Utilise dinoCount s'il n'est pas null/undefined, sinon 0
6
7// Chaînage optionnel (?.) - disponible dans les versions récentes de JS
8const species = dinosaur?.species; // Accède en toute sécurité à la propriété, même si dinosaur est null/undefinedCas de conversion de type intéressants et délicats
Certaines conversions de type en JavaScript peuvent être surprenantes, semblables au comportement inhabituel des dinosaures après un orage :
1// Cas étranges d'égalité faible (==)
2[] == ''; // true (un tableau vide est converti en chaîne vide)
3[1] == 1; // true (le tableau [1] est converti en chaîne "1", puis en nombre 1)
4[1, 2] == '1,2'; // true (le tableau [1, 2] est converti en chaîne "1,2")
5true == '1'; // true (true est converti en 1, et '1' en 1)
6false == '0'; // true (false est converti en 0, et '0' en 0)
7null == undefined; // true (cas particulier dans la spécification)
8'' == 0; // true (la chaîne vide est convertie en 0)
9
10// Opérations avec NaN
11NaN == NaN; // false (NaN n'est égal à rien, pas même à lui-même)
12Number.isNaN(NaN); // true (la bonne façon de vérifier NaN)
13
14// Opérations avec des objets
15const obj1 = {}, obj2 = {};
16obj1 == obj2; // false (les objets sont comparés par référence, pas par contenu)
17obj1 === obj2; // false (les objets sont comparés par référence, pas par contenu)
18
19// Opérations sur les tableaux
20[] + []; // "" (les tableaux sont convertis en chaînes, puis joints)
21[] + {}; // "[object Object]" (l'objet est converti en chaîne)
22{} + []; // 0 ({} vide est traité comme un bloc de code, et +[] est converti en nombre)Bonnes pratiques
Pour éviter les surprises lorsqu'on travaille avec des types de données, il vaut la peine de suivre ces règles - elles sont comme les protocoles de sécurité de Jurassic Park :
1. Utilise la comparaison stricte (===, !==)
1// MAUVAIS
2if (dinoCount == "5") { // Fonctionnera, mais peut mener à des bugs
3
4// BON
5if (dinoCount === 5) { // Indique clairement que dinoCount devrait être un nombre2. Convertis explicitement les types lorsque c'est nécessaire
1// MAUVAIS
2const totalVisitors = visitorCount + newVisitors; // Peut donner des résultats incorrects si l'une des variables est une chaîne
3
4// BON
5const totalVisitors = Number(visitorCount) + Number(newVisitors); // Conversion explicite en nombres3. Utilise des méthodes de vérification de type appropriées
1// MAUVAIS
2if (typeof height == "number" && !isNaN(height)) { // Fonctionne, mais est imprécis
3
4// BON
5function isValidNumber(value) {
6 return typeof value === 'number' && !isNaN(value) && isFinite(value);
7}
8if (isValidNumber(height)) {4. Sois prudent avec les opérations sur les objets
1// MAUVAIS
2if (dinosaur == otherDinosaur) { // Compare les références, pas le contenu
3
4// BON
5function isEqual(obj1, obj2) {
6 return JSON.stringify(obj1) === JSON.stringify(obj2); // Pour les objets simples
7}
8if (isEqual(dinosaur, otherDinosaur)) {5. Utilise les opérateurs de coalescence des nuls (??) et de chaînage optionnel (?.)
1// AU LIEU DE
2const safeVisitorCount = visitorCount !== null && visitorCount !== undefined ? visitorCount : 0;
3const speciesName = dinosaur && dinosaur.species ? dinosaur.species : "Unknown";
4
5// MIEUX (en JS récent)
6const safeVisitorCount = visitorCount ?? 0;
7const speciesName = dinosaur?.species ?? "Unknown";Exemple pratique : traitement des données de dinosaures
L'exemple suivant montre comment appliquer les opérations sur les types dans un scénario pratique :
1// Données provenant de diverses sources (simulation d'API, formulaires, fichiers CSV)
2const rawDinoData = [
3 { id: "1", name: "Rexy", species: "T-Rex", height: "5.6", dangerous: "true", lastFed: "2023-05-15T08:30:00" },
4 { id: 2, name: "Blue", species: "Velociraptor", height: "1.8", dangerous: true, lastFed: "2023-05-15T09:15:00" },
5 { id: "3", name: "Spike", species: "Stegosaurus", height: 4.2, dangerous: "false", lastFed: null },
6 { id: "4", name: "Cera", species: "Triceratops", height: "unknown", dangerous: false, lastFed: "invalid-date" }
7];
8
9// Fonction pour normaliser et valider les données
10function processDinosaurData(dinoList) {
11 // Préparer le tableau normalisé
12 const processedData = [];
13
14 // Traiter chaque élément
15 for (let i = 0; i < dinoList.length; i++) {
16 const dino = dinoList[i];
17
18 // Normaliser l'ID
19 const id = Number(dino.id);
20 if (isNaN(id) || id <= 0) {
21 console.warn(`Dinosaure ignoré avec un ID invalide : ${dino.id}`);
22 continue;
23 }
24
25 // Normaliser le nom
26 const name = String(dino.name).trim();
27 if (name === "") {
28 console.warn(`Dinosaure ignoré sans nom, ID : ${id}`);
29 continue;
30 }
31
32 // Normaliser l'espèce
33 const species = String(dino.species).trim() || "Unknown";
34
35 // Normaliser la taille
36 let height;
37 if (dino.height === "unknown" || dino.height === undefined) {
38 height = null;
39 } else {
40 height = Number(dino.height);
41 if (isNaN(height)) {
42 console.warn(`Taille invalide pour ${name}, mise à null`);
43 height = null;
44 }
45 }
46
47 // Normaliser le drapeau dangerous
48 let dangerous;
49 if (typeof dino.dangerous === 'string') {
50 dangerous = dino.dangerous.toLowerCase() === 'true';
51 } else {
52 dangerous = Boolean(dino.dangerous);
53 }
54
55 // Normaliser la date du dernier nourrissage
56 let lastFed = null;
57 if (dino.lastFed) {
58 const date = new Date(dino.lastFed);
59 if (!isNaN(date.getTime())) {
60 lastFed = date;
61 } else {
62 console.warn(`Date de nourrissage invalide pour ${name}`);
63 }
64 }
65
66 // Calculs supplémentaires
67 const securityLevel = dangerous ? (height > 3 ? "High" : "Medium") : "Low";
68 const daysFromLastFeed = lastFed ? Math.floor((new Date() - lastFed) / (1000 * 60 * 60 * 24)) : null;
69
70 // Ajouter le dinosaure normalisé au tableau de résultats
71 processedData.push({
72 id,
73 name,
74 species,
75 height,
76 dangerous,
77 lastFed,
78 securityLevel,
79 daysFromLastFeed,
80 needsFeeding: daysFromLastFeed === null || daysFromLastFeed > 1
81 });
82 }
83
84 return processedData;
85}
86
87// Utilisation de la fonction
88const normalizedDinos = processDinosaurData(rawDinoData);
89console.log(normalizedDinos);
90
91// Traitement supplémentaire des données
92const dangerousDinos = normalizedDinos.filter(dino => dino.dangerous);
93const withHeight = normalizedDinos.filter(dino => dino.height !== null);
94const avgHeight = withHeight.reduce((sum, dino) => sum + dino.height, 0) / withHeight.length;
95const dinosBySecurityLevel = normalizedDinos.reduce((groups, dino) => {
96 groups[dino.securityLevel] = groups[dino.securityLevel] || [];
97 groups[dino.securityLevel].push(dino);
98 return groups;
99}, {});Cet exemple montre comment gérer différents types de données, les convertir, les valider et les normaliser - toutes des opérations fondamentales que les scientifiques de Jurassic Park auraient besoin d'effectuer sur les données quotidiennes.
Résumé
La conversion de type et les opérations sur les types de données en JavaScript est un sujet vaste qui requiert de comprendre de nombreuses nuances. Les aspects clés sont :
Conversion implicite - JavaScript convertit automatiquement les types dans de nombreux contextes
- Peut mener à des résultats inattendus
- Est pratique mais parfois dangereuse
Conversion explicite - Transformation de type contrôlée
String(),Number(),Boolean()- fonctions de conversiontoString(),parseInt(),parseFloat()- méthodes et fonctions spécialisées!!- conversion rapide en booléen
Opérations sur les types individuels
- Les chaînes ont un riche ensemble de méthodes pour manipuler le texte
- Les nombres peuvent être traités à l'aide d'opérateurs et de l'objet Math
- Les valeurs booléennes sont le fondement des instructions conditionnelles
- Null et undefined ont des règles particulières dans les opérations
Bonnes pratiques
- Utiliser la comparaison stricte (===, !==)
- Convertir explicitement les types lorsque c'est nécessaire
- Utiliser des fonctions de vérification appropriées
Tout comme à Jurassic Park, où différentes espèces de dinosaures requièrent différents protocoles de manipulation, en JavaScript différents types de données requièrent l'approche appropriée. La connaissance des règles de conversion et des opérations sur les types permet une manipulation efficace et sûre des données - le fondement de toute application JavaScript.
Dans la prochaine leçon, nous examinerons les opérateurs arithmétiques et d'affectation, qui permettent des calculs plus avancés - essentiels pour gérer les ressources dans une entreprise aussi complexe que Jurassic Park.
Code de cette leçon : index.js
1// Conversion de types et opérations sur les types
2// Expérimente la conversion implicite et explicite des types en JavaScript
3
4// === Conversion implicite (Type Coercion) ===
5console.log("=== Conversion implicite ===");
6
7// String + Number -> concaténation
8console.log("Dinosaures : " + 5); // "Dinosaures : 5"
9console.log("5" + 3); // "53" (string !)
10
11// String - Number -> Number
12console.log("10" - 3); // 7
13console.log("5" * 2); // 10
14
15// Boolean dans les opérations
16console.log(true + 1); // 2
17console.log(false + 1); // 1
18
19// === Conversion explicite ===
20console.log("\n=== Conversion explicite ===");
21
22// Vers Number
23console.log(Number("42")); // 42
24console.log(Number("abc")); // NaN
25console.log(parseInt("100px")); // 100
26console.log(parseFloat("3.14m")); // 3.14
27
28// Vers String
29console.log(String(42)); // "42"
30console.log(String(true)); // "true"
31console.log((255).toString(16)); // "ff" (hex)
32
33// Vers Boolean
34console.log(Boolean(0)); // false
35console.log(Boolean("")); // false
36console.log(Boolean("texte")); // true
37console.log(Boolean(1)); // true
38
39// === Opérateur typeof ===
40console.log("\n=== typeof ===");
41console.log(typeof 42); // "number"
42console.log(typeof "texte"); // "string"
43console.log(typeof true); // "boolean"
44console.log(typeof undefined); // "undefined"
45console.log(typeof null); // "object" (bug historique !)
46
47// Ta mission :
48// 1. Vérifie le résultat de "5" + 3 vs "5" - 3
49// 2. Utilise Number() pour convertir une chaîne en nombre
50// 3. Vérifie typeof pour différentes valeurs
51Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que renvoie l'expression Number('hello') en JavaScript ?
2. Que renvoie l'expression '5' - 2 en JavaScript ?
3. Quelle méthode de conversion explicite d'une chaîne en nombre est INCORRECTE ?
4. Laquelle des valeurs suivantes N'EST PAS une valeur falsy en JavaScript ?
Tâches pratiques dans le jeu
- Tri horizontal
Classe les éléments du littéral de gabarit :