Le JavaScript a bien changé depuis quelques années. Ce cours récapitule les éléments fondamentaux de syntaxes en JavaScript depuis sa version ES6.
Depuis votre navigateur, cliquez droit puis inspectez l'élément. Vous accédez alors à une console REPL en JavaScript.
let
déclare une variable à l'intérieur d'un scope.
let x = 10;
console.log(x); // 10
{
let x = 2;
console.log(x); // 2
}
console.log(x); // 10
const
fonctionne pareillement mais pour les constantes.
const x = 10;
console.log(x); // 10
{
const x = 2;
console.log(x); // 2
}
console.log(x); // 10
const x = 2; // erreur
Une variable déclarée avec let
et const
est défini dans le reste du bloc dans lequel cette variable est déclarée.
Considérons par exemple le code :
function testDePortee() {
return x;
}
// console.log(testDePortee()); // ReferenceError
let x = "foo";
console.log(testDePortee()); // "foo"
Avant ES6, on utilisait le mot clé var
pour la déclaration d'une variable.
Ce mot clé a une comportement paradoxal : il "hisse" une variable déclarée en haut d'une fonction.
Par exemple :
function testDePortee(position) {
if(false) {
var x = "ce bloc ne devrait rien changer, non ?"
}
return x;
}
var x = "foo";
console.log(testDePortee()); // undefined
En fait, ce dernier bout de code est équivalent à :
function testDePortee(position) {
var x;
if(false) {
x = "ce bloc ne devrait rien changer, non ?"
}
return x;
}
var x = "foo";
console.log(testDePortee()); // undefined
L'utilisation de let
plutôt que de var
est également à privilégier pour éviter de polluer l'environnement global par des variables ayant une portée trop large.
En effet, une variable définie à l'aide de var
persiste au delà d'un bloc, contrairement à let
:
{
var privee = 1;
}
console.log(privee); // 1
{
let privee = 1;
}
console.log(privee); // ReferenceError
L'introduction du backtick (ou accent grave) simplifie la gestion des chaînes de caractères :
const a = 1, b = 5, c = 6;
// Avant ES6
console.log(a + " + " + b + " = " + c);
// Après ES6
console.log(`${a} + ${b} = ${c}`);
// Encore mieux :
console.log(`${a} + ${b} = ${a + b}`);
Ces modèles de libellé autorisent les chaînes multi-lignes :
const menu = `<ul>
<li>Accueil</li>
<li>A propos</li>
</ul>`
console.log(modele);
function myFunction(x, y = 10) {
// y is 10 if not passed or undefined
return x + y;
}
myFunction(5); // will return 15
C'est une manière plus synthétique d'écrire des fonctions, sans le mot clé function
.
Si la fonction se contente de retourner une valeur, on peut même omettre le
mot clé keyword
et les accolades.
// ES5
function mult_ES5(x, y) {
return x * y;
}
var bar = mult2_ES5(x, y) {
return x * y;
}
// ES6
const mult_ES6 = (x, y) => { return x * y };
// lorsque la fonction se contente de retourner une valeur, on omet les accolades et le mot clé return
const mult2_ES6 = (x, y) => x * y;
// lorsque la fonction ne prend qu'un seul paramètre, l'omission des parenthèses autour des paramètres est permise
const print = x => console.log(x);
Une classe est un type de fonction, qui est initialisée avec class
et dont les propriétés sont assignées par la méthode constructor()
.
class Car {
constructor(brand) {
this.carname = brand;
}
}
mycar = new Car("Ford");
Le langage ES6 concise la manipulation des tableaux, que ce soit pour obtenir les éléments d'un tableau :
const outils = ["dégau rabot", "scie circulaire", "scie à onglet", "meuleuse"]
// Avant ES6
const premier = outils[0], troisieme = outils[2];
console.log(premier, troisieme); // 1 3
// Après ES6
const [, second, , quatrieme] = outils;
console.log(second, quatrieme); // 2 4
ou pour échanger des valeurs :
let connecte = true, deconnecte = false;
// Avant ES6
var tmp = connecte;
connecte = deconnecte;
deconnecte = tmp;
// Après ES6
[connecte, deconnecte] = [deconnecte, connecte]
C'est encore plus pratique avec les tableaux associatifs :
// Avant ES6
function marges() {
var gauche=1, droite=2, haut=3, bas=4;
return { gauche: gauche, droite: droite, haut: haut, bas: bas };
}
var data = marges(),
gauche = data.gauche,
bas = data.bas;
console.log(gauche, bas); // 1 4
// Après ES6
function marges() {
const gauche=1, droite=2, haut=3, bas=4;
return { gauche, droite, haut, bas };
}
const { gauche, bas } = marges();
console.log(gauche, bas); // 1 4
On peut utiliser cette nouvelle syntaxe même dans les paramètres d'une fonction :
const utilisateur = { prenom: "John", nom: "Doe"};
function nameToString({ prenom, nom }) {
return `${nom}, ${prenom}`;
}
console.log(nameToString(utilisateur)); // John Doe
ou l'utiliser de manière récursive pour une structure de données à plusieurs étages :
const themes = {
couleur: { principale: "blue", secondaire: "gray" },
traduction: { accueil: {en: "Home", fr: "Accueil" },
};
// on initialise ici "texte"
const { traduction: { accueil: {fr: texte }}} = themes
// c'est équivalent à :
// const texte = themes.traduction.accueil.fr
// mais c'est nettement plus concis pour extraire plusieurs variables
console.log(texte); // Accueil
Cette syntaxe est très nouvelle (ES9 en vigueur depuis 2018), mais elle s'avère très utile.
Une fonction peut prendre un nombre inconnu de paramètres : Math.max(2, 4, 5, 6)
. Mais comment faire lorsque ces paramètres sont stockés dans un tableau ?
Math.max([2, 4, 5, 6]) // NaN
Auparavant, la solution consistait à utiliser la fonction apply
pour convertir les éléments de la liste en une série de paramètres :
Math.max.apply(Math, [2, 4, 5, 6]) // 6
Le nouvel opérateur de décomposition allège significativement la syntaxe :
Math.max(...[2, 4, 5, 6]) // 6
On peut également l'utiliser dans une fonction pour lui permettre d'accepter un nombre inconnu de paramètres :
max = (...arguments) => {
let result = -Infinity;
for(const value of arguments) {
if(value > result) {
result = value;
}
}
return result;
}
Les arrays ne sont pas nouveau à ES6.
Retourne le premier élément d'une liste qui passe une fonction de test.
const numbers = [4, 9, 16, 25, 29];
const threshold = (value, index, array) => {
return value > 18;
}
const first = numbers.find(threshold);
console.log(first); // 25
// plus synthétiquement avec une fonction anonyme et sans les paramètres inutilisées :
console.log(
numbers.find(
value => value > 18
)
);
Retourne l'index.
map retourne une liste de la même taille.
const performSomething = (item) => {
//...
return item
}
const items = ['a', 'b', 'c']
const newArray = items.map((item) => performSomething(item))
filter retourne une liste avec moins d'éléments : uniquement ceux qui passent la fonction de filtrage.
// Avec une boucle
const items = [
{ name: 'a', content: { /* ... */ }},
{ name: 'b', content: { /* ... */ }},
{ name: 'c', content: { /* ... */ }}
]
for (const item of items) {
if (item.name === 'b') {
return item
}
}
// Sans boucle
const b = items.find((item) => item.name === 'b')
const b = items.filter((item) => item.name === 'b').shift()
Applique un traitement à chaque élément d'une liste.
const items = ['a', 'b', 'c']
items.forEach((item) => {
performSomething(item)
})
Ces fonctions font partis du paradigme déclaratif, contrairement à une approche impérative.
ES6 introduit une nouvelle syntaxe pour alléger les forEach
:
const titres = ["col1", "col2", "col3", "col4"];
const lineWidth = 40;
console.log("-".repeat(lineWidth));
const colWidth = Math.round(lineWidth / titres.length );
let line = "|"
for (const name of titres) {
line += ` ${name}${" ".repeat(colWidth - 3 - name.length)} |`;
}
console.log(line);
Pour pouvoir suivre ce cours sur React, il est nécessaire de maîtriser convenablement les fondamentaux de JavaScript.
Si vous vous sentez encore mal à l'aise, voici quelques ressources à lire ou à écouter :