Aller au contenu

b

JavaScript

Tout au long du cours, nous avons un objectif et un besoin d'apprendre une quantité suffisante de JavaScript en plus du développement Web.

JavaScript a progressé rapidement au cours des dernières années et dans ce cours, nous utilisons les fonctionnalités des versions les plus récentes. Le nom officiel de la norme JavaScript est ECMAScript. À l'heure actuelle, la dernière version est celle publiée en juin 2021 sous le nom ECMAScript®2021, également connue sous le nom d'ES12.

Les navigateurs ne prennent pas encore en charge toutes les nouvelles fonctionnalités de JavaScript. De ce fait, une grande partie du code exécuté dans les navigateurs a été transpilé d'une version plus récente de JavaScript vers une version plus ancienne et plus compatible.

Aujourd'hui, la façon la plus populaire de transpiler est d'utiliser Babel. La transpilation est automatiquement configurée dans les applications React créées avec create-react-app. Nous reviendrons plus en détail sur la configuration de la transpilation dans la partie 7 de ce cours.

Node.js est un environnement d'exécution JavaScript basé sur le moteur JavaScript Chrome V8 de Google et fonctionne pratiquement n'importe où - des serveurs aux téléphones mobiles. Entraînons-nous à écrire du JavaScript en utilisant Node. Il est prévu que la version de Node.js installée sur votre machine soit au moins la version 16.13.2. Les dernières versions de Node comprennent déjà les dernières versions de JavaScript, le code n'a donc pas besoin d'être transpilé.

Le code est écrit dans des fichiers se terminant par .js qui sont exécutés en émettant la commande node name_of_file.js

Il est également possible d'écrire du code JavaScript dans la console Node.js, qui s'ouvre en tapant node dans la ligne de commande, ainsi que dans la console de l'outil de développement du navigateur. Les dernières révisions de Chrome gèrent assez bien les nouvelles fonctionnalités de JavaScript sans transpiler le code. Vous pouvez également utiliser un outil tel que JS Bin.

JavaScript rappelle en quelque sorte, à la fois par son nom et sa syntaxe, Java. Mais en ce qui concerne le mécanisme de base du langage, ils ne pourraient pas être plus différents. Venant d'un arrière-plan Java, le comportement de JavaScript peut sembler un peu étranger, surtout si l'on ne fait pas l'effort de rechercher ses fonctionnalités.

Dans certains cercles, il a également été populaire d'essayer de "simuler" les fonctionnalités Java et les modèles de conception en JavaScript. Nous vous déconseillons de le faire car les langues et les écosystèmes respectifs sont finalement très différents.

Variables

En JavaScript, il existe plusieurs façons de définir des variables :

const x = 1
let y = 5

console.log(x, y)   // 1, 5 est affiché
y += 10
console.log(x, y)   // 1, 15 est affiché
y = 'sometext'
console.log(x, y)   // 1, sometext est affiché
x = 4               // provoque une erreur

const ne définit pas réellement une variable mais une constante dont la valeur ne pourra plus être modifiée. D'autre part, let définit une variable normale.

Dans l'exemple ci-dessus, nous voyons également que le type des données affectées à la variable peut changer pendant l'exécution. Au début y stocke un entier et à la fin une chaîne.

Il est également possible de définir des variables en JavaScript à l'aide du mot clé var. var a longtemps été le seul moyen de définir des variables. const et let n'ont été ajoutés que récemment dans la version ES6. Dans des situations spécifiques, var fonctionne différemment des définitions de variables dans la plupart des langages - voir JavaScript Variables - Should You Use let, var or const? on Medium ou Keyword: var vs. let on JS Tips pour plus d'informations. Pendant ce cours, l'utilisation de var est déconseillée et vous devriez vous en tenir à const et let ! Vous pouvez en savoir plus sur ce sujet sur YouTube - par ex. var, let et const - Fonctionnalités JavaScript ES6

Tableaux

Un array et quelques exemples d'utilisation :

const t = [1, -1, 3]

t.push(5)

console.log(t.length) // 4 est affiché
console.log(t[1])     // -1 est affiché

t.forEach(value => {
  console.log(value)  // les chiffres 1, -1, 3, 5 sont affichés, chacun sur une ligne
})                    

Il convient de noter dans cet exemple le fait que le contenu du tableau peut être modifié même s'il est défini en tant que const. Comme le tableau est un objet, la variable pointe toujours vers le même objet. Cependant, le contenu du tableau change à mesure que de nouveaux éléments y sont ajoutés.

Une façon de parcourir les éléments du tableau consiste à utiliser forEach comme indiqué dans l'exemple. forEach reçoit une fonction définie en utilisant la syntaxe des flèches comme paramètre.

value => {
  console.log(value)
}

forEach appelle la fonction pour chacun des éléments du tableau, en passant toujours l'élément individuel comme argument. La fonction en tant qu'argument de forEach peut également recevoir d'autres arguments.

Dans l'exemple précédent, un nouvel élément a été ajouté au tableau à l'aide de la méthode push. Lors de l'utilisation de React, des techniques de programmation fonctionnelle sont souvent utilisées. L'une des caractéristiques du paradigme de la programmation fonctionnelle est l'utilisation de structures de données immuables. Dans le code React, il est préférable d'utiliser la méthode concat, qui n'ajoute pas l'élément au tableau, mais crée un nouveau tableau dans lequel le contenu de l'ancien tableau et le nouvel élément sont tous deux inclus.

const t = [1, -1, 3]

const t2 = t.concat(5)

console.log(t)  // [1, -1, 3] est affiché
console.log(t2) // [1, -1, 3, 5] est affiché

L'appel de méthode t.concat(5) n'ajoute pas un nouvel élément à l'ancien tableau mais renvoie un nouveau tableau qui, en plus de contenir les éléments de l'ancien tableau, contient également le nouvel élément.

Il existe de nombreuses méthodes utiles définies pour les tableaux. Examinons un court exemple d'utilisation de la méthode map.

const t = [1, 2, 3]

const m1 = t.map(value => value * 2)
console.log(m1)   // [2, 4, 6] est affiché

Sur la base de l'ancien tableau, map crée un nouveau tableau, pour lequel la fonction donnée en paramètre est utilisée pour créer les éléments. Pour cet exemple, la valeur d'origine est multipliée par deux.

Map peut également transformer le tableau en quelque chose de complètement différent :

const m2 = t.map(value => '<li>' + value + '</li>')
console.log(m2)  
// [ '<li>1</li>', '<li>2</li>', '<li>3</li>' ] est affiché

Ici, un tableau rempli de valeurs entières est transformé en un tableau contenant des chaînes HTML à l'aide de la méthode map. Dans la partie 2 de ce cours, nous verrons que map est utilisée assez fréquemment dans React.

Les éléments individuels d'un tableau sont faciles à affecter à des variables à l'aide de l'affectation par déstructuration.

const t = [1, 2, 3, 4, 5]

const [first, second, ...rest] = t

console.log(first, second)  // 1, 2 est affiché
console.log(rest)          // [3, 4, 5] est affiché

Grâce à l'affectation, les variables first et second recevront comme valeurs les deux premiers entiers du tableau. Les nombres entiers restants sont "regroupés" dans un tableau qui leur est propre, qui est ensuite affecté à la variable rest.

Objets

Il existe différentes manières de définir des objets en JavaScript. Une méthode très courante consiste à utiliser object literals, qui se produit en répertoriant ses propriétés entre accolades :

const object1 = {
  name: 'Arto Hellas',
  age: 35,
  education: 'PhD',
}

const object2 = {
  name: 'Full Stack web application development',
  level: 'intermediate studies',
  size: 5,
}

const object3 = {
  name: {
    first: 'Dan',
    last: 'Abramov',
  },
  grades: [2, 3, 5, 3],
  department: 'Stanford University',
}

Les valeurs des propriétés peuvent être de n'importe quel type, comme des entiers, des chaînes, des tableaux, des objets...

Les propriétés d'un objet sont référencées en utilisant la notation "point" ou en utilisant des crochets :

console.log(object1.name)         // Arto Hellas est affiché
const fieldName = 'age' 
console.log(object1[fieldName])    // 35 est affiché

Vous pouvez également ajouter des propriétés à un objet à la volée en utilisant la notation par points ou les crochets :

object1.address = 'Helsinki'
object1['secret number'] = 12341

Le dernier des ajouts doit être fait en utilisant des crochets, car lors de l'utilisation de la notation par points, le numéro secret n'est pas un nom de propriété valide en raison du caractère espace.

Naturellement, les objets en JavaScript peuvent également avoir des méthodes. Cependant, pendant ce cours, nous n'avons pas besoin de définir des objets avec des méthodes qui leur sont propres. C'est pourquoi ils ne sont abordés que brièvement pendant le cours.

Les objets peuvent également être définis à l'aide de fonctions dites constructeurs, ce qui se traduit par un mécanisme rappelant de nombreux autres langages de programmation, par ex. Les classes de Java. Malgré cette similitude, JavaScript n'a pas de classes au même sens que les langages de programmation orientés objet. Il y a eu, cependant, un ajout de la syntaxe de classe à partir de la version ES6, qui dans certains cas aide à structurer les classes orientées objet.

Les fonctions

Nous nous sommes déjà familiarisés avec la définition des fonctions fléchées. Le processus complet pour définir une fonction flechée est le suivant :

const sum = (p1, p2) => {
  console.log(p1)
  console.log(p2)
  return p1 + p2
}

et la fonction est appelée comme on peut s'y attendre :

const result = sum(1, 5)
console.log(result)

S'il n'y a qu'un seul paramètre, nous pouvons exclure les parenthèses de la définition :

const square = p => {
  console.log(p)
  return p * p
}

Si la fonction ne contient qu'une seule expression, les accolades ne sont pas nécessaires. Dans ce cas, la fonction ne renvoie que le résultat de sa seule expression. Maintenant, si nous supprimons l'impression de la console, nous pouvons encore raccourcir la définition de la fonction :

const square = p => p * p

Cette forme est particulièrement pratique lors de la manipulation de tableaux - par ex. lors de l'utilisation de la méthode map :

const t = [1, 2, 3]
const tSquared = t.map(p => p * p)
// tSquared est devenu [1, 4, 9]

La fonctionnalité de fonction fléchée a été ajoutée à JavaScript il y a seulement quelques années, avec la version ES6. Avant cela, la seule façon de définir des fonctions était d'utiliser le mot-clé function.

Il existe deux façons de référencer la fonction ; on donne un nom dans une déclaration de fonction.

function product(a, b) {
  return a * b
}

const result = product(2, 6)
// result est maintenant 12

L'autre façon de définir la fonction consiste à utiliser une expression de fonction. Dans ce cas, il n'est pas nécessaire de donner un nom à la fonction et la définition peut résider dans le reste du code :

const average = function(a, b) {
  return (a + b) / 2
}

const result = average(2, 5)
// result est maintenant 3.5

Pendant ce cours, nous définirons toutes les fonctions en utilisant la syntaxe des flèches.

Objets, Méthodes et "this"

Étant donné que pendant ce cours, nous utilisons une version de React contenant des React Hooks, nous n'avons pas besoin de définir des objets avec des méthodes. Le contenu de ce chapitre n'est pas pertinent pour le cours mais est certainement bon à savoir à bien des égards. En particulier, lors de l'utilisation d'anciennes versions de React, il faut comprendre les sujets de ce chapitre.

Les fonctions fléchées et les fonctions définies à l'aide du mot-clé function varient considérablement en ce qui concerne leur comportement par rapport au mot-clé this, qui fait référence à l'objet lui-même.

On peut assigner des méthodes à un objet en définissant des propriétés qui sont des fonctions :

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'PhD',
  greet: function() {    console.log('hello, my name is ' + this.name)  },}

arto.greet()  // "hello, my name is Arto Hellas" est affiché

Les méthodes peuvent être affectées aux objets même après la création de l'objet :

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'PhD',
  greet: function() {
    console.log('hello, my name is ' + this.name)
  },
}

arto.growOlder = function() {  this.age += 1}
console.log(arto.age)   // 35 est affiché
arto.growOlder()
console.log(arto.age)   // 36 est affiché

Modifions légèrement l'objet :

const arto = {
  name: 'Arto Hellas',
  age: 35,
  education: 'PhD',
  greet: function() {
    console.log('hello, my name is ' + this.name)
  },
  doAddition: function(a, b) {    console.log(a + b)  },}

arto.doAddition(1, 4)        // 5 est affiché

const referenceToAddition = arto.doAddition
referenceToAddition(10, 15)   // 25 est affiché

Maintenant, l'objet a la méthode doAddition qui calcule la somme des nombres qui lui sont donnés en tant que paramètres. La méthode est appelée de manière habituelle, en utilisant l'objet arto.doAddition(1, 4) ou en stockant une référence de méthode dans une variable et en appelant la méthode via la variable : referenceToAddition(10, 15).

Si nous essayons de faire la même chose avec la méthode greet, nous rencontrons un problème :

arto.greet()       // "hello, my name is Arto Hellas" est affiché

const referenceToGreet = arto.greet
referenceToGreet() // affiche "hello, my name is undefined"

Lors de l'appel de la méthode via une référence, la méthode perd la connaissance de ce qu'était le this d'origine. Contrairement à d'autres langages, en JavaScript, la valeur de this est définie en fonction de comment la méthode s'appelle. Lors de l'appel de la méthode via une référence, la valeur de this devient le soi-disant objet global et le résultat final n'est souvent pas ce que le développeur de logiciels avait initialement prévu.

Perdre la trace de this lors de l'écriture de code JavaScript soulève quelques problèmes potentiels. Des situations surviennent souvent où React ou Node (ou plus précisément le moteur JavaScript du navigateur Web) doit appeler une méthode dans un objet que le développeur a défini. Cependant, dans ce cours, nous évitons ces problèmes en utilisant le "this-less" JavaScript.

Une situation conduisant à la "disparition" de this survient lorsque nous définissons un délai d'attente pour appeler la fonction greet sur l'objet arto, en utilisant le setTimeout.

const arto = {
  name: 'Arto Hellas',
  greet: function() {
    console.log('hello, my name is ' + this.name)
  },
}

setTimeout(arto.greet, 1000)

Comme mentionné, la valeur de this en JavaScript est définie en fonction de la façon dont la méthode est appelée. Lorsque setTimeout appelle la méthode, c'est le moteur JavaScript qui appelle réellement la méthode et, à ce stade, this fait référence à l'objet global.

Il existe plusieurs mécanismes par lesquels le this original peut être préservé. L'une d'entre elles utilise une méthode appelée bind :

setTimeout(arto.greet.bind(arto), 1000)

L'appel de arto.greet.bind(arto) crée une nouvelle fonction où this pointe vers Arto, indépendamment de l'endroit et de la manière dont la méthode est appelée.

En utilisant les fonctions fléchées, il est possible de résoudre certains des problèmes liés à this. Ils ne doivent cependant pas être utilisés comme méthodes pour les objets car alors this ne fonctionne pas du tout. Nous reviendrons plus tard sur le comportement de this par rapport aux fonctions fléchées.

Si vous souhaitez mieux comprendre comment this fonctionne en JavaScript, Internet regorge de documents sur le sujet, par ex. la série de screencasts Understand JavaScript's this Keyword in Depth par egghead.io est fortement recommandé !

Les classes

Comme mentionné précédemment, il n'y a pas de mécanisme de classe en JavaScript comme ceux des langages de programmation orientés objet. Il existe cependant des fonctionnalités permettant de "simuler" des classes orientées objet.

Jetons un coup d'oeil à la syntaxe de classe qui a été introduite dans JavaScript avec ES6, qui simplifie considérablement la définition des classes (ou des choses semblables à des classes) en JavaScript.

Dans l'exemple suivant, nous définissons une "classe" appelée Person et deux objets Person :

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  greet() {
    console.log('hello, my name is ' + this.name)
  }
}

const adam = new Person('Adam Ondra', 35)
adam.greet()

const janja = new Person('Janja Garnbret', 22)
janja.greet()

En ce qui concerne la syntaxe, les classes et les objets créés à partir de celles-ci rappellent beaucoup les classes et objets Java. Leur comportement est également assez similaire aux objets Java. Au coeur, ce sont toujours des objets basés sur l'héritage prototypal de JavaScript . Le type des deux objets est en fait Object, puisque JavaScript ne définit essentiellement que les types Boolean, Null, Undefined, Number, String, Symbol, BigInt et Object.

L'introduction de la syntaxe de classe était un ajout controversé. Découvrez Not Awesome: ES6 Classes ou Is "Class" In ES6 The New "Bad" Part ? sur Medium pour plus de détails.

La syntaxe de la classe ES6 est beaucoup utilisée dans "l'ancien" React et aussi dans Node.js, donc sa compréhension est bénéfique même dans ce cours. Cependant, comme nous utilisons la nouvelle fonctionnalité Hooks de React tout au long de ce cours, nous n'avons aucune utilisation concrète de la syntaxe de classe de JavaScript.

Matériaux JavaScript

Il existe à la fois de bons et de mauvais guides pour JavaScript sur Internet. La plupart des liens de cette page relatifs aux fonctionnalités JavaScript font référence au Guide JavaScript de Mozilla.

Il est fortement recommandé de lire immédiatement A re-introduction to JavaScript (JS tutorial) sur le site Web de Mozilla.

Si vous souhaitez connaître JavaScript en profondeur, il existe une excellente série de livres gratuits sur Internet appelée You-Dont-Know-JS.

Une autre excellente ressource pour apprendre JavaScript est javascript.info.

egghead.io propose de nombreux screencasts de qualité sur JavaScript, React et d'autres sujets intéressants. Malheureusement, une partie du matériel est derrière un paywall.