Javascript

Propriété exclusive du formateur: Fabio Ginja

Les Variables

Variables - Déclaration

Une variable correspond à un espace mémoire de l'ordinateur dans lequel on stockera une valeur. Lors de la déclaration de la variable, on la nommera afin de faire référence à cet espace mémoire.

Les variables sont donc composées de deux éléments: un nom et une valeur.

Nom de la variable

Valeur/contenu de la variable

var name = "Fabio";
var isAwake = true;
var nbEcrans = 2;

Par convention, le nom d'une variable s'écrit en camelCase.

Variables - Primitive Types

Le javascript est un langage faiblement typé, et typé de façon dynamique.

Voyons d'abord les types primitifs:

var boolean = true;
var string = "Chaîne de caractères"; // Simple ou double quote
var number = 3.14; // Peut être un int ou un float
var notDefined; // La viariable est déclarée, mais non définie
typeof(notDefined); // undefined
var isNull = null;
typeof(isNull): // object
var symbol = Symbol(); // Symbole unique

On parle aussi de "scalar types".

var x = 3;
var y = x;
x = 5;
console.log(y) // affichera 3

La valeur de "y" ne change pas (elle ne devient pas 5). On stocke bien une valeur dans la variable.

Variables - Reference Types

Contrairement aux types primitifs les références ne stockent pas une valeur, mais une référence à un espace mémoire...
D'abord voyons les différents types:

var array = ["pomme", "fraise", "banane", 5, true, null]; // les tableaux
typeof(array); // array

var object = {
  nom: "Pierre",
  age: "25",
};
typeof(object); // object

var test = function() {
  console.log("Ceci est une fonction test");
}
typeof(test); // function

Use Strict

Il est possible de déclarer une variable "à la volée" (sans var) mais c'est une (très) mauvaise pratique car cela rend sa portée globale.

function test() {
  var name = "Fabio";
  number = 10; // 💩 DON'T DO THIS - La variable devient globale car initialisé sans "var"
}
test();
// Ici, on a accès à la variable "number", mais pas à "name"
var note = "fa";
var note = "do"; // 💩 Cela est possible mais à ne pas faire

Il est possible d'insérer "use strict"; en haut de son document, ce qui génère une erreur si on déclare des variables globales de façon accidentelle ou en cas de faute de frappe.

"use strict";
number = 15; // ❌ Error!
var note = "fa";
var note = "do"; // ❌ Error!

On peut également déclarer "use strict"; au sein d'une fonction:

name = "Fabio"; 💩 // DON'T DO THIS
function test() {
  "use strict";
  number = 10; // ❌ Error
}

ES6 - let, const

ECMAscript est un ensemble de normes concernant le javascript. La version 6 apporte son lot de nouveautés: on a désormais deux nouvelles façons de déclarer des variables.

const name = "Fabio";
name = "Batman"; // ❌ error: "name" is read-only
let day = "lundi";
day = "mardi"; // Ok

Lorsqu'on déclare une variable avec const, on précise que sa valeur ne va pas changer.

La différence entre let et var concerne la porté de la variable.

  • var est function-scoped
  • let et const  sont bloc-scoped

Scope - Portée

function fn() {
  if (true) {
    var isAlive = true;
  }
  console.log(isAlive); // renvoie true
}
function fn() {
  var isAlive;
  if (true) {
    isAlive = true;
  }
  console.log(isAlive);
}
fn(); // Ok

function fn() {
  // traitement...
}

La variable est remontée au haut du corp du script ou de la fonction. C'est également valable pour les fonctions:

Ces deux exemples sont équivalent. Cela est dû au hoisting (remontée de variable).

var est function-scoped, voici un exemple:

function block() {
  if (true) {
    let isAlive = true;
  }
  console.log(isAlive); // ❌ Error
}

En revanche, const et let n'ont que la porté du bloc où ils sont déclarés (ici, le bloc if).

Conclusion: ne plus utiliser var

Manipuler les objets

Un objet javascript se compose de deux éléments: une propriété et une valeur.

const user = {
  name: "Pierre",
  age: "25",
};

Pour créer une nouvelle propriété job de user, on écrira:

Pour accéder à la propriété name de user, on utilisera la syntaxe suivante: 

nomObjet.nomPropriété;
/* Ou Encore */
nomObjet["nomPropriété"];

// Dans notre exemple
user.name;
user["name"];
user.job = "Dev";
// Ou encore
user["job"] = "Dev";

Comment NE PAS copier un objet

Petite expérience:

Que se passe t'il si on écrit ce code?

const user = {
  name: "Pierre",
  age: "25",
};
const secondUser = user; // ❌ A ne pas utiliser...
secondUser.name = "Marion";
console.log(user.name);

Ici on ne copie que la référence. "user" et "secondUser" pointent tous les deux vers le même objet/espace mémoire. Modifier ce qui se trouve à cette adresse mémoire impactera donc "user" et "secondUser".
Cela est également valable pour les tableaux et les fonctions.

Comment copier un objet
Spread Operator

On peut utiliser le spread operator pour copier un objet:

const user = {
  name: "Pierre",
  age: "25",
};
// ⚠️ Attention, cela n'effectue cependant qu'une copie superficielle de ce dernier (shallow copy).
const secondUser = [...user]; // ✅ Browser et node
secondUser.name = "Marion";
console.log(user.name); // Pierre

Ou bien utiliser la fonction native structuredClone:

const user = {
  name: "Pierre",
  age: "25",
};
const secondUser = structuredClone(user); // ✅ Browser - Copie profonde
secondUser.name = "Marion";
console.log(user.name); // Pierre

Manipuler les tableaux

Un tableau peut contenir différentes valeurs. Celles-ci ne sont pas obligées d'être du même type, on peut mettre ainsi dans un tableau:

  • string
  • number
  • array
  • object
  • function
  • etc...
array[0] // pomme
array[3] // 5

Pour accéder à un élément du tableau, il faut faire référence à son index:

Petite expérience:

const firstArray = ["pomme", "fraise", "banane", 5, true, null];
const secondArray = firstArray; // ❌ A ne pas utiliser
secondArray[0] = "cerise";
const myArray = ["pomme", "fraise", "banane", 5, true, null];
console.log(myArray.length); // 6 - Taille du tableau
myArray.push("new"); // Ajoute "new" à la fin du tableau
myArray.pop(); // Supprime le dernier élément du tableau

Que va t'il se passer?

ES6 - Template Literals

// ES5 - concaténation
const name = "Fabio";
console.log("Bonjour " + name);
// ES6 - String interpolation
const name = "Fabio";
console.log(`Bonjour ${name}`);

Les back quotes ont aussi l'avantage de garder les caractères spéciaux comme les sauts de ligne.

Une autre nouveauté d'ES6 permet de manipuler plus aisément les chaînes de caractères:

Pour écrire une chaîne de caractères, on peut donc utiliser les simple ('), double (") ou back (`) quotes.

 

Lorsque vous utiliser la back quotes, vous pouvez faire appels à une expression ou une variable javascript en utilisant la syntaxe suivante:

// ES6
const name = "Fabio";
console.log(`Bonjour ${name}. Il fait ${10 + 7}° dehors.
	Bonne journée.`);

Les Fonctions

Écrire une fonction

Une fonction est un ensemble d'instructions. Une fonction peut prendre un, plusieurs, ou aucun paramètre. L'avantage d'une fonction est de pouvoir répéter les mêmes instructions à différentes reprises avec potentiellement des paramètres différents.

// Déclaration d'une fonction
function sayHello() {
  console.log("Hello!");
}

sayHello(); // Affiche "Hello!"

// Avec un paramètre
function sayHelloName(name) {
  console.log(`Hello ${name}!`);
}

sayHelloName("Fabio"); // Affiche "Hello Fabio!"

Une fonction peut aussi retourner quelque-chose:

function add(x, y) {
  return x + y;
}

Fonction Callback

Il est également possible de passer une fonction en paramètre d'une autre fonction:

// Déclaration d'une fonction
function sayHello() {
  console.log("Hello!");
}

sayHello(); // Affiche "Hello!"

// Avec un paramètre
function withCallback(callback) {
  // Traitement de la fonction...
  console.log("withCallback appelée");
  callback(); // on appelle callback après le traitement
}

withCallback(sayHello); // Affiche "withCallback appelée" puis "Hello!"

En javascript, on a très souvent recours à des callbacks.

IIFE

Une IIFE (Immediately Invoked Function Expression) est une fonction qui s'appelle elle-même. Cette dernière a une autre utilité: la portée de toute les variables à l'intérieur sera locale (par rapport à l'extérieur de la fonction.
Voici sa syntaxe:

// IIFE
(function () {
  // Traitement...
})();

Une IIFE peut également prendre un ou plusieurs paramètres.

// IIFE
(function (x, y) {
  console.log(x + y);
})(1, 2);
// Affichera 3

ES6 - Arrow Function

Une arrow function (fonction fléchée) permet d'avoir un syntaxe plus courte qu'une fonction classique. Cependant, une arrow function conserve toujours son contexte d'origine.

// Fonction classique - Etape 0
function square(x) {
  return x * x;
}

// Etape 1 - Je stock dans une variable une fonction anonyme
const square = function (x) {
  return x * x;
}

// Etape 2 - Je supprime le mot clé function et j'ajoute une flèche entre les paramètres et le corp de la fonction
const square = (x) => {
  return x * x;
}

// Etape 3 - Si jamais il n'y a qu'UN et UN SEUL paramètre, on peut supprimer les parenthèses de ce dernier:
const square = x => {
  return x * x;
}

ES6 - Arrow Function (2)

Attention cependant si vous faites un return implicite d'un objet:

// Etape 3 - Si jamais il n'y a qu'UN et UN SEUL paramètre, on peut supprimer les parenthèses de ce dernier:
const square = (x) => {
  return x * x;
}

// Etape 4 - Si la fonction n'a qu'une seule ligne de traitement, et que cette ligne est un return,
// alors on peut faire un return implicite en supprimant le mot clé return ainsi que les accolades du corps de la fonction.
const square = x => x * x;
function returnObject() {
  return {language: "Javascript"};
}
const returnObject = () => {language: "Javascript"}; // ❌
const returnObject = () => ({language: "Javascript"}); // ✅

Moins de code = moins d'erreurs

ES6 - Default Parameters

Il est possible, lors de la déclaration d'une fonction, de lui passer des paramètres qui auront une valeur par défaut:

let cart = 0;
function addToCart(quantity = 1) {
  cart += quantity;
}

addToCart();  // cart = 1
addToCart(4); // cart = 5

En ES5, on aurait dû écrire:

function addToCart(quantity) {
  if (quantity === undefined)
    quantity = 1;
  cart += quantity;
}

ES6 - Rest Parameters

On peut également créer une fonction qui accepte un nombre inconnu d'arguments:

const add = (...numbers) => {
  let result = 0;
  for (const number of numbers) {
    result += number;
  }
  return result;
}
add(): // 0
add(5, 10, 20); // 35
add(1, 4); //5

On peut avoir un argument nommé en début de liste suivi de rest parameters:

const add = (first, ...numbers) => {
  console.log(first);
  let result = 0;
  for (const number of numbers) {
    result += number;
  }
  return result;
}

add(5, 10, 20); // Affiche 5 - renvoie 30

ES6 - Rest/Spread operator

Le spread operator est un moyen de passer plusieurs arguments à une variable ou à une fonction:

const add = (...numbers) => { // Rest Operator
  let result = 0;
  for (const number of numbers) {
    result += number;
  }
  return result;
}
const arrNumbers = [5, 10, 20];
add(...arrNumbers); // Result: 35 - Spread Operator

Cette méthode peut également être utilisée pour copier un tableau ou un objet. Attention, cela n'effectue cependant qu'une copie superficielle de ce dernier (shallow copy).

const user = {
  role: "user",
  level: 1,
}

const secondUser = {
  ...user, // Spread Operator
  role: "admin",
  points: 1000,
}
const info = ["admin", 1,];
// Spread Operator
const secondinfor = [...info, 1000,];

ES6 - le trailing comma n'est plus une erreur.

Le dernier élément d'un objet ou tableau peut avoir une virgule, c'est considéré comme une bonne pratique.

Closure

Une closure est une fonction ayant accès à une variable qui est à l'extérieur de son propre scope:

let counter = 1;

const addFive = () => {
  return counter + 5;
}
addFive(); // returns 6

Cela diffère donc d'une fonction pure qui elle ne dépendrait d'aucune variable extérieure. Les closures sont utiles pour modifier l'état globale mais prennent de fait plus de mémoire que les fonctions pures. On peut aussi encapsuler une fonction dans une autre fonction.

const outer = () => {
  // Closure
  let counter = 1;

 return () => {
    return counter + 5;
  }
}
const addFive = outer();
addFive(); // returns 6

Exercice

A vous de jouer!

1. Créer une fonction qui affichera le paramètre dans la console.
	ex: log(10) -> Affiche "10" dans la console
	ex: log("Bonjour") -> Affiche "Bonjour" dans la console

2. Écrire une fonction qui prend en paramètre une température, et retourne un objet décrivant l'état de l'eau à cette température.
- On considère que l'eau est à des conditions normales de pression (gèle sous 0°, vapeur au-dessus de 100°)
	ex. h2o(-5) -> retourne {etat: "glace"}
	ex. h2o(5) -> retourne {etat: "liquide"}
	ex. h2o(150) -> retourne {etat: "vapeur"}

3. Écrire une fonction prenant 2 paramètres. Vérifier si le premier est multiple du second et renvoyer un booléen selon le cas.

4. Écrire une fonction qui donne le factoriel du nombre passé en paramètre.
- En math, factoriel de 5 est équivalent à 5 * 4 * 3 * 2 * 1. On l'écrit "5!". Vu autrement, la factoriel de 5 est égale à "5 * 4!"...
	ex: factoriel(5) -> retourne 120
    
5. Écrire une fonction qui retournera le résultat de la suite de Fibonacci du nombre passé en paramètre.
	ex: fibo(10) -> retourne 55

6. Afficher le résultat des fonctions précédentes dans la console grâce à votre fonction "log".

Les Boucles

For, for of

Syntaxe de la boucle for:

for (initialisation; condition; expressionFinale) {
  traitement;
}

for (let i = 1; i <= 10; i++) {
  console.log(i);
}

Exercice:

Parcourez et afficher chaque élément du tableau suivant à l'aide d'une boucle for:

const avengers = ["Iron man", "Captain America", "Thor", "Hulk", "Black Widow", "Hawkeye"];

Syntaxe de la boucle for of:

for (const hero of avengers) {
  console.log(hero);
}

Itérer dans un tableau

Méthode ES5: forEach

const cities = ["Tokyo", "Salvador", "Moscow", "Berlin", "Nairobi", "Rio", "Denver", "Helsinki", "Oslo"];

cities.forEach((city, index) => {
  console.log(`${city} est à l'index ${index}`);
});
const numbers = [1, 2, 3, 4, 5];

const doubleNumbers = numbers.map((number, index) => {
  console.log(`${number} est à l'index ${index}`);
  return number * 2;
}):
doubleNumbers; // [2, 4, 6, 8, 10]

La fonction forEach ne retourne rien.

Méthode ES6: map✔️

Cette méthode renvoie un nouveau tableau, celui d'origine n'est pas modifié.

Filter, reduce

La méthode filter crée et retourne un nouveau tableau contenant tous les éléments du tableau d'origine qui remplissent une condition déterminée par la fonction callback. (source MDN)

const cities = ["Tokyo", "Salvador", "Moscow", "Berlin", "Nairobi", "Rio", "Denver", "Helsinki", "Oslo"];

const result = cities.filter(city => city.length > 6);

console.log(result); // ["Salvador", "Nairobi", "Helsinki"]

La méthode reduce applique une fonction qui est un « accumulateur » et qui traite chaque valeur d'une liste (de la gauche vers la droite) afin de la réduire à une seule valeur. (source MDN)

const numbers = [1, 2, 3, 4, 5];

const doubleNumbers = numbers.reduce((accumulator, number) => {
  return accumulator + number;
}, 0);
console.log(doubleNumbers); // [2, 4, 6, 8, 10]

Some, every

La méthode some teste si au moins un élément du tableau passe le test implémenté par la fonction callback. Elle renvoie un booléen.

const cities = ["Tokyo", "Salvador", "Moscow", "Berlin", "Nairobi", "Rio", "Denver", "Helsinki", "Oslo"];

const result = cities.some(city => city.length > 6);

console.log(result); // true

La méthode every teste si tout les éléments du tableau vérifient une condition donnée.

const numbers = [1, 2, 3, 4, 5];

const supTo0 = numbers.every(number => number > 0);
const supTo2 = numbers.every(number => number > 2);

console.log(supTo0); // true
console.log(supTo2); // false

Find, findIndex, includes

La méthode find renvoie la valeur qui remplie la condition donnée par la fonction callback, ou undefined si aucun élément ne la remplie.

const numbers = [1, 2, 3, 4, 5];

const result = numbers.find(number => number > 6); // undefined
const result2 = numbers.find(number => number > 2); // 3

La méthode findIndex renvoie l'index de la valeur remplissant la condition donnée par la fonction callback, sinon elle renvoie -1.

const numbers = [1, 2, 3, 4, 5];

const result = numbers.findIndex(number => number > 6); // -1
const result2 = numbers.findIndex(number => number > 2); // 2

La méthode includes permet de déterminer si un tableau contient une valeur et renvoie true si c'est le cas, false sinon.

const avengers = ["Iron man", "Captain America", "Thor", "Hulk", "Black Widow", "Hawkeye"];

const result = avengers.includes(hero => hero === "Dr Strange"); // false
const result2 = avengers.includes(hero => hero === "Thor"); // true

Itérer dans un objet

Méthode ES5: for in

const character = {
  name: "Daenerys",
  house: "Targaryen",
  gender: "female",
}

for (var prop in character) {
  if (character.hasOwnProperty(prop)) {
    // Traitement
  }
}
Object.keys(character); // ["name", "house", "gender"]
Object.values(character); // ["Daenerys", "Targaryen", "female"]
Object.entries(character); // [["name", "Daenerys"], ["house", "Targaryen"], ["gender", "female"]]

⚠️Cette boucle peut causer des erreurs si on ne vérifie pas si la propriété appartient bien à l'objet et non au prototype.

Méthode ES6: ✔️ Transformer l'objet en tableau grâce à

  • Object.keys
  • Object.values
  • Object.entries

Exercice

A vous de jouer!

1. Écrire une fonction qui détermine si le nombre passé en paramètre est un nombre premier.
    
2. Écrire une fonction qui donne le factoriel du nombre passé en paramètre. Il faudra utiliser une boucle.
    
3. Écrire une fonction qui retournera le résultat de la suite de Fibonacci du nombre passé en paramètre. Il faudra utiliser une boucle.

4. Écrire une fonction prenant n paramètres. Vérifier si les n+1 paramètres sont multiples du premier et renvoyer un booléen selon le cas.

5. Vous avez un tableau d'objet qui contient la valeur des champs et un booléen pour déterminer si une erreur est présente dans ces champs (d'un formulaire).
- Renvoyer un seul message d'erreur si le champs contient une ou plusieurs erreurs.
- Sinon renvoyer "ok".
[
  {username: "test", error: false,},
  {email: "test@email", error: true,},
  {password: "a", error: true,},
]

6. Renvoyer un message d'erreur pour chaque champs du formulaire qui contient une erreur. Sinon renvoyer "ok".

Bind & this (OOP)

this

En javascript, il est possible d'associer une méthode à un objet. Il est possible de le faire de plusieurs manières:

const person = {
  account: 10000,
  // avec le mot clé function
  work: function() {
    this.account += 1000;
  },
  // Ou en la déclarant directement
  printAccount() {
    console.log(this.account);
  }
}

person.work();
person.printAccount();

Afin de préciser de quel "account" on fait référence, on précise bien qu'il s'agit de la propriété de l'objet avec le mot clé this.

bind

Cependant, si jamais on affecte la méthode d'un objet à une variable, elle devient une fonction, et perd le contexte:

const person = {
  // ...
  work: function() {
    this.account += 1000;
  },
  // ...
}

const goWork = person.work; // ❌
goWork(); // undefined

Afin de lier la fonction "goWork" à l'objet "person", on utilisera bind:

const work = person.work.bind(person); // ✔️
work(); // Ok ✔️

bind (2)

Il est également possible de déclarer une fonction puis de la lier à un objet:

function showAge() {
  console.log(this.age)
}

const martin = {
  age: 18
}

const showMartinAge = showAge.bind(martin)
showMartinAge() // ✔️ 18

showAge() // ❌ undefined

On pourra remarquer qu'ici, il n'y a aucun ";". En javascript, on peut s'en passer sachant que le compilateur les mettra à notre place. Cela peut néanmoins provoquer certaines erreurs dans des cas particuliers (IIFE).

call, apply

La méthode apply() appelle une fonction en lui passant une valeur this et des arguments sous forme d'un tableau (ou d'un objet semblable à un tableau).

function showAge(firstname, lastname) {
  console.log(firstname, lastname, this.age)
}

const martin = {
  age: 18
}

showAge.apply(martin, ["Paul", "Dupont"]) // Paul Dupont 18

La méthode call() réalise un appel à une fonction avec une valeur this donnée et des arguments fournis individuellement.

function describePerson(firstname, lastname) {
  console.log(firstname, lastname, this.age)
}

const martin = {
  age: 18
}

describePerson.call(martin, "Paul", "Dupont") // Paul Dupont 18

Exercice

A vous de jouer!

1. Créer une fonction et la lier avec un objet. Cette fonction devra prendre au moins deux paramètres.
Cette fonction devra également utiliser le mot clé this.
  -ex: function fn(param1, param2)

Prototypes (OOP)

Object.create()

Pour construire un objet avec des méthodes, et que ce dernier soit réutilisable, il est plus aisé d'utiliser Object.create():

const event = {
 getDate: function() {
    console.log(`${this.name} aura lieu en ${this.date}.`)
  }
}

const coupeDuMonde = Object.create(event)
coupeDuMonde.name = "Coupe du monde"
coupeDuMonde.date = 2022
coupeDuMonde.getDate() // Coupe du monde aura lieu en 2022.

⚠️Attention, si on modifie "getDate" dans event, la méthode sera modifiée immédiatement sur tout les objets.

coupeDuMonde.getDate() // Coupe du monde aura lieu en 2022.
event.getDate = () => console.log("Don't work anymore")
coupeDuMonde.getDate() // "Don't work anymore

new Object

On va d'abord créer une fonction (avec une lettre capitale) sur laquelle on pourra appliquer un constructeur. On pourra ajouter des méthodes à cet objet avec prototype puis "instancier" cet objet avec new.

function Event(name, date) {
  this.name = name;
  this.date = date;
}

Event.prototype.getDate = function() {
  console.log(`${this.name} aura lieu en ${this.date}.`)
}

const someEvent = new Event("Euro 2020", 2021)
someEvent.getDate() // Euro 2020 aura lieu en 2021.

Ou encore:

function Event(name, date) {
  this.name = name;
  this.date = date;
  this.getDate = () => {
    console.log(`${this.name} aura lieu en ${this.date}.`)
  }
}

Que fait new?

const prototype = {
  getDate() {
    console.log(`${this.name} aura lieu en ${this.date}.`);
  }
}
Object.setPrototypeOf(someEvent, prototype)

3. this est passé comme valeur à la fonction prototype.

someEvent.name = "Euro 2020"
someEvent.date = 2021

1. Il crée un nouvel objet.

2. Il lie cet objet à un autre objet en le définissant comme son prototype.

const someEvent = {}

4. Si la fonction ne renvoie pas d'objet, this est renvoyé

someEvent = {
  name: "Euro 2020",
  date: 2021,
  getDate() {console.log(`${this.name} aura lieu en ${this.date}.`);}
}

Exercice

A vous de jouer!

1. Créer un objet avec une méthode avec Object.create()

2. Créer un objet avec une méthode avec new

Classes (OOP)

class

Les classes n'existent pas vraiment en javascript. Le mot clé class est simplement une nouvelle implémentation de la création d'objet tel que vue précédemment.

class Pokemon {
  constructor(name, type) {
    this.name = name
    this.type = type
  }

  useAttack(attack = 'Charge') {
    console.log(`${this.name} utilise ${attack} pour attaquer!`)
  }

  static getTotal() {
    console.log('Il y a 151 pokémons')
  }
}

On peut ensuite l'instancier comme suit:

const pikachu = new Pokemon('Pikachu', 'electrique')
pikachu.useAttack() // Pikachu utilise Charge pour attaquer!
Pokemon.getTotal() // Il y a 151 pokémons

extends

On peut également extend une classe à partir d'une autre. Voici comment faire:

class SuperPokemon extends Pokemon {
  constructor(name, type, specialMove) {
    super(name, type)
    this.specialMove = specialMove
  }

  useSpecial() {
    console.log(`${this.name} utilise son attaque spéciale: ${this.specialMove}`)
  }
}
const dracofeu = new SuperPokemon('Dracofeu', 'feu', 'Lance-Flammes')
dracofeu.useSpecial()

Propriété privée

On peut également rendre une propriété privée (et donc inaccessible via son instance) en la nommant avec #:

class Colors {
  // #colors devient inaccessible de à l'extérieur de la classe
  #colors = ['red', 'green', 'blue']

  get totalColors() {
    return this.#colors.length
  }

  set addColor(newColor) {
    this.#colors.push(newColor)
  }
}
const allColors = new Colors()
allColors.totalColors // 3
allColors.addColor = 'black'
allColors.totalColors // 4

Par conséquent, pour accéder aux propriétés privées, il faudra le faire via des getter et des setter.

Exercice

A vous de jouer!

1. Créer une classe (ex: vehicule) et étendre (extend) cette classe à une autre (ex: moto)

Javascript dans le web

Script

Pour exécuter du javascript, il faudra écrire une balise <script> dans notre html. On pourra écrire du javascript directement dans le corps de cette balise, ou alors faire référence à un fichier avec l'attribut src tout en précisant le type:

<script>
  console.log("Javascript dans le corp de script")
</script>
<script type="text/javascript" src="index.js"></script>

Or, le chargement de la balise script est "bloquant" et empêche le chargement des autres éléments de la page html. Pour résoudre ce soucis, on va préciser les attributs async (afin d'en faire le chargement de façon asynchrone) et defer (pour différer l'exécution du script à la fin du chargement de la page).

<script type="text/javascript" src="index.js" async defer></script>

Window

L'objet window est disponible lorsqu'on ouvre notre console dans notre navigateur. Il correspond à notre fenêtre.

// Quelques informations:
window.open() // Ouvre une nouvelle fenêtre.
window.close() // Ferme la fenêtre en cours.
window.prompt() // Ouvre la boîte de dialogue d'impression du document en cours.
window.alert() // Affiche une boîte de message d'alerte.
window.scroll() // Fait défiler la fenêtre à un endroit particulier dans le document.
window.scrollTo() // Fait défiler à un jeu de coordonnées particulier dans le document.
window.setInterval(() => console.log(5), 1000) // retourne un id
window.clearInterval(id) // prend en paramètre l'id de setInterval
window.setTimeout() // exécute la fonction après le timeout
window.close // détermine si la fenêtre est fermée
window.location // détermine sur quelle page on est (url)
window.scrollY // position de l'axe vertical du scroll
window.innerHeight // Hauteur de la fenêtre
window.innerWidth // Largeur de la fenêtre

Document

L'objet document est un sous objet de window , il ne correspond pas à la fenêtre mais bien à la page html.

// Sélection des éléments html
document.getElementById(id) // Retourne l'élèment possiédant l'id défini
document.getElementsByClassName(classe) // Retourne un array possédant la classe définie
document.getElementsByTagName(balise) // Retourne un array de la balise définie
document.getElementsByName(valeur) // Retourne un array des éléments ayant pour attribut name la valeur définie
document.querySelector(selecteur) // Retourne le premier élément qui correspond au sélécteur passé en paramètre (sélécteur css)
document.querySelectorAll() // Retourne un tableau
// Création d'un élément
document.createElement("div") // créer une balise div

Element

Voyons quelques propriétés utiles pout manipuler les éléments html.

// Sélection des éléments html
element.classname // Permet de modifier la classe de l'élément
element.classList // Retourne un array des classes de l'élément
element.attributes // Permet de récupérer les attributs
element.children // Retourne un array des enfants de l'élément
element.id // Retourne l'id de l'élément 
element.innerHTML // Permet de modifier l'html de l'élément
element.innerText // Permet de modifier le texte de l'élément
element.scrollTop // Définit ou obtient le nombre de pixels dont le contenu de l'élément a défilé vers le haut.

Exercice

A vous de jouer!

Capturing & Bubbling

Bubbling

Le bubbling est le fait qu'un événement va se propagé d'un élément (balise HTML) enfant vers les éléments parents.

<style>
  body * {
    margin: 10px;
    border: 1px solid blue;
  }
</style>

<section onclick="alert('Clicked on section')">Section
  <article onclick="alert('Clicked on article')">Article
    <p onclick="alert('Clicked on paragraph')">Lorem ipsum, dolor sit amet consectetur adipisicing elit.</p>
  </article>
</section>

Ici, le clique sur la balise p va se propager a l'article, puis a la section. On aura donc l'apparition 3 boites de dialogue successives (paragraph, puis article, puis section).

Target & currentTarget

On peut différencier l'element qui a été cible lors du click grace a event.target.

event.currentTarget nous permet lui d'obtenir l'element courant vers lequel l'événement s'est propagé.

<section onclick="onClickHandler(event, 'Clicked on article')">
  Section
  <article onclick="onClickHandler(event, 'Clicked on article')">
    Article
    <p onclick="onClickHandler(event, 'Clicked on paragraph')">
      Lorem ipsum, dolor sit amet consectetur adipisicing elit.
    </p>
  </article>
</section>
<script>
  function onClickHandler(event, message) {
    alert(`${message} - Event: ${event.target.nodeName} - CurrentTarget: ${event.currentTarget.nodeName}`)
  }
</script>

Stop the bubbling

Si on souhaite ne pas propager un événement au parent, alors on pourra utiliser la méthode event.stopPropagation.

<section onclick="onClickHandler(event, 'Clicked on article')">
  Section
  <article onclick="onClickHandler(event, 'Clicked on article')">
    Article
    <p onclick="onClickHandler(event, 'Clicked on paragraph')">
      Lorem ipsum, dolor sit amet consectetur adipisicing elit.
    </p>
  </article>
</section>
<script>
  function onClickHandler(event, message) {
    event.stopPropagation()
    alert(`${message} - Event: ${event.target.nodeName} - CurrentTarget: ${event.currentTarget.nodeName}`)
  }
</script>

Dans cet exemple, le clique ne se propage plus aux parents. On aura donc qu'une seule alerte - seulement sur l'élément effectivement cliqué.

StopImmediatePropagation

Si un element a plusieurs event handlers - à savoir plusieurs ecouteurs sur le meme evenement - alors il faudra arreter le propagation sur chacun de ces event handlers, ou a defaut, utiliser la methode event.stopImmediatePropagation.

document.querySelector('p').addEventListener('click', () => {
	console.log('Cette fonction ne va jamais s\'éxécuter')
})
function onClickHandler(event, message = null) {
	event.stopImmediatePropagation()
	alert(`${message} - Event: ${event.target.nodeName} - CurrentTarget: ${event.currentTarget.nodeName}`)
}

Capturing

La phase de capture est l'inverse de la phase de Bubbling. Lors de la phase de bubbling, les événements remontent de l'enfant vers les parents.
Lors de la phase de capture, les événements vont du parents vers la cible.

<body>
  <section>Section
    <article>Article
      <p onclick="onClickHandler(event, 'Clicked on paragraph')">Lorem ipsum, dolor sit amet consectetur adipisicing elit. Incidunt, hic.</p>
    </article>
  </section>
<body>

Pour cliquer sur notre paragraphe, notre page va d'abord détecter le clique sur la balise html, puis body, puis section, puis article, pour enfin trouver notre balise p.

Capturing - suite

On peut attacher des actions lors de la phase de capture comme suit:

document.querySelector('p').addEventListener('click', (event) => {
  console.log('AddEventListener')
}, true)

Grace a notre 3eme argument, on precise qu'on souhaite executer cette fonction lors de la phase de capture et non lors de la phase de bubbling.

Dans les faits, cette phase est très rarement utilisée.

La propriété event.eventPhase nous donne la phase de notre événement (capturing=1, target=2, bubbling=3).

Event

Type d'événements

Il existe de très nombreux type d'événements que l'on peu écouter en javascript. Cette liste est toujours en train de s'accroitre avec notamment les possibilités des smartphones. On peut voir la liste sur la documentation officielle.

Une fois un evement choisi, afin de l'ecouter, on pourra utiliser directement la methode addEventListener sur l'object que l'on souhaite ecouter:

element.addEventListener(eventType, callback, capturePhase)

Exercice - Créer un écouteur d'événement:

  • sur le click
  • lors du redimensionnement de la fenêtre
  • lors du changement d'un input
  • lors de la soumission d'un formulaire
  • lors d'un appui sur la touche Esc
  • lors d'un changement d'orientation du mobile

Création d'évènements

Il est également possible de créer un évènement custom grâce a la classe Event:

const newEvent = new Event("nomDeMonEvent", { bubbles: true, cancelable: false, composed: false })
  • bubbles precise si l'évènement va avoir un effet de bubbling ou non (false par défaut)
  • cancelable precise si l'évènement est annulable ou non (false par défaut)
  • composed indique si l'évènement déclenchera les écouteurs en dehors d'une racine shadow (false par défaut)

Pour appeler cet évènement par la suite, il faudra utiliser la méthode dispatchEvent:

element.dispatchEvent(newEvent)

Exercice

A vous de jouer!

1. Créer un évènement qui se déclenche sur les cliques des bouttons et lors des doubles cliques des h1.

JQuery

Utilité

JQuery a connu une très forte popularité il y a quelques années car la librairie proposait des solution simples à des problèmes récurrents qu'on pouvait rencontrer:

  • simplicité pour sélectionner un element du DOM
  • appels HTTP simplifié avec AJAX
  • animations faciles à réaliser
  • compatible avec tout les navigateurs

Exemples de code avec JQuery:

$( "button.continue" ).html( "Next Step..." )

const hiddenBox = $( "#banner-message" );
$( "#button-container button" ).on( "click", function( event ) {
  hiddenBox.show();
});

$.ajax({
  url: "/api/getWeather",
  data: { zipcode: 97201 },
  success: function( result ) {
    $( "#weather-temp" ).html( "<strong>" + result + "</strong> degrees" );
  }
});

Cheat Sheet

Aujourd'hui, la bibliothèque est de moins en moins utilisés car le langage (Javascript) s'est développer pour apporter des solutions sans librairie externe, mais aussi du fait de l'essor des framework (React, Angular, Vue, Svelte...).

Recherches JQuery sur Google de 2004 à juin 2020:

Vous trouverez sur ce lien une "feuille de triche"/feuille memo-technique avec les différents fonctions/méthodes disponibles avec JQuery.

Gestion d'erreur

Error()

Lorsqu'on écrit une fonction, il est possible de générer et renvoyer des erreurs. Pour générer une erreur il suffit d'écrire:

throw Error('Error message');

Le mot clé throw permet de lever une exception. Error() permet d'envoyer un message d'erreur indiquant le document dans lequel  l'erreur a eu lieu ainsi que sa ligne.

SyntaxError(); // erreur de syntaxe
TypeError(); // erreur de type
ReferenceError(); // déréférencement d'une référence invalide
RangeError(); // erreur quand une variable numérique ou un paramètre est en dehors de sa plage de validité

Error est générique, mais on a d'autre générateur d'erreurs:

Afin de gérer une erreur au sein de notre code, on peut utiliser l'instruction try catch.

Cette liste n'est pas exhaustive. Plus d'information sur le site MDN

try catch finally

try catch nous permet d'exécuter le code du bloc try. Si jamais une exception est levée dans le bloc try, on stoppe alors l’exécution du code de ce bloc pour passer au bloc catch. Dans tout les cas, on ira au bloc finally (mais écrire ce bloc est optionnel).

function isItFabio(name) {
  if (name !== 'Fabio') throw Error('This is not Fabio');
  console.log('Hello Fabio');
}

try {
  isItFabio('Nope');
} catch (err) {
  console.error(err);
} finally {
  console.log('finally called');
}

On remarquera que l'erreur est passée au bloc catch en paramètre, et que l'on l'affichera dans la console d'erreur (console.error).

Exercice

A vous de jouer!

1. Écrire une fonction qui additionne deux nombres.
Cette fonction devra gérer les cas d'erreurs (les renvoyer avec throw) et écrire un try catch afin de gérer les erreurs de façon sensible.
En fin de traitement, "bravo" doit être affiché dans la console.

Asynchrone

Promise

Une promesse est un objet qui représente la complétion ou l'échec d'une opération asynchrone.

Pour créer une promesse, il suffit d'utiliser le mot clé new et l'objet Promise():

const users = ["John", "Jessica"]

const getUsers = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve(users)
    } else {
      reject("Faillure")
    }
  }, 1000)
})

Question: Que verra t'on si l'on faisait un console.log de "getUsers"?

console.log(getUsers) // Promise { <pending> }

resolve() est invoqué si tout s'est bien passé pendant notre traitement, et reject() est invoqué en cas d'erreur.

then

Comment obtenir la réponse d'une promesse? Son traitement étant asynchrone, on a un moyen d’exécuter du code lors de la résolution de la promesse. Syntaxe:

promise.then(fonctionSiSucces, fonctionSiEchec)
getUsers.then(
  users => console.log(users[0]), 
  err => console.log("Error :(", err)
)

then est très utile, cependant on perd quelque peu en lisibilité lorsqu'on a des promesses chaînées (à la chaîne). Il est également possible d'utiliser catch afin de récupérer l'erreur.

getUsers
  .then(users => console.log(users[0])
  .catch(err => console.log("Error :(", err))

ES6 - async, await

Il existe également un autre moyen de rendre le code synchrone, s’exécutant ligne par ligne, même avec une promesse. Pour cela, il faut rendre la fonction asynchrone avec le mot clé async:

async function getFirstUser() {...}
// Ou encore
const getFirstUser = async () => {...}

Une fois cela fait, on peut maintenant utiliser le mot clé await dans le corps de la fonction afin de ne pas continuer la lecture du code temps que la promesse ne s'est pas résolue.

const getFirstUser = async () {
  try {
    let usersArray = await getUsers
    return console.log(usersArray[0])
  } catch (err) {
    return console.log("Error :(", err)
  }
}

Appels HTTP

fetch

Par définition, un appel à une base de donnée est asynchrone. On  ne sait pas si la requête va réussir ou échouer ni quand elle va se résoudre. L'API fetch nous permet de remplacer XMLHTTPRequest en simplifiant le code.

Voyons comment faire un appel à une API avec fetch:

fetch(url, {options}) // Retourne une promesse

fetch('https://randomuser.me/api/')
  .then(response => response.json())
  .then(result => {
    console.log(result)
  })
  .catch(error => {
    console.log(error)
  })

Exercice: transformer ce code avec async await.

XML

Le XML (Extensible Markup Language) comme le JSON sont des formats utilisés pour l'envoi de données lors des requêtes HTTP. Le XML a l'avantage d'être plus descriptif, balisé avec des délimitations claires:

<employees>
  <employee>
    <firstName>John</firstName> <lastName>Doe</lastName>
  </employee>
  <employee>
    <firstName>Anna</firstName> <lastName>Smith</lastName>
  </employee>
  <employee>
    <firstName>Peter</firstName> <lastName>Jones</lastName>
  </employee>
</employees>

JSON

JSON (JavaScript Object Notation) est proche du XML mais présente pour avantage d'être plus court (et donc des appels HTTP plus performants) et peux utiliser un tableau javascript dans ses résultats

{"employees":[
  { "firstName":"John", "lastName":"Doe" },
  { "firstName":"Anna", "lastName":"Smith" },
  { "firstName":"Peter", "lastName":"Jones" }
]}

Aujourd'hui, c'est ce dernier qui est largement utilisé dans le web. Le XML reste parfois utiliser notamment pour des fichiers de configuration (JAVA).

Exemple de fausse API utilisant le JSON:

Stocker les données

Cookies vs LocalStorage vs SessionStorage

Plusieurs solutions existent pour stocker des informations en JS pour persister des informations autre qu'en mémoire (in memory - dans une variable javascript).

LocalStorage

Plusieurs solutions existent pour stocker des informations en JS pour persister des informations autre qu'en mémoire (in memory - dans une variable javascript).

// Sauvegarder une valeur dans le localStorage
localStorage.setItem("name", "Fabio");
localStorage.setItem("data", JSON.stringify(["Cracovie", "Munich"]));

// Accéder à une valeur
localStorage.getItem("name"); // Fabio
JSON.parse(localStorage.getItem("data")); // ["Cracovie", "Munich"]

// Supprimer une valeur
localStorage.removeItem("data");

// Supprimer toutes les valeurs
localStorage.clear();

⚠️ Attention, ne pas utiliser le localStorage pour stocker des informations sensibles ou des tokens de connexion (le localStorage est accessible par le JS et les informations peuvent être dérobées si le site est vulnerable aux attaques XSS).

SessionStorage

SessionStorage est très semblable au localStorage. Cependant, les informations en session ne sont conservées que jusqu'à la fermeture du navigateur.

// Sauvegarder une valeur dans le sessionStorage
sessionStorage.setItem("name", "Fabio");
sessionStorage.setItem("data", JSON.stringify(["Cracovie", "Munich"]));

// Accéder à une valeur
sessionStorage.getItem("name"); // Fabio
JSON.parse(sessionStorage.getItem("data")); // ["Cracovie", "Munich"]

// Supprimer une valeur
sessionStorage.removeItem("data");

// Supprimer toutes les valeurs
sessionStorage.clear();

⚠️ Attention, ne pas utiliser le sessionStorage pour stocker des informations sensibles ou des tokens de connexion (vulnerable aux attaques XSS).

Cookies

Un cookie est utile pour transporter de l'information entre le client et le serveur. Ce dernier est plus léger et peut contenir des informations plus sensibles. Cependant pour que ce dernier soit sécuriser, il ne faut pas qu'il soit accessible par le javascript (http only et secure).

document.cookie = "user=John; max-age=120; secure; samesite";

⚠️ Attention, un cookie non httpOnly est vulnerable aux attaques CSRF. L'option httpOnly est précisée par le serveur et non par le client. Lorsque l'option httpOnly est précisée, le client n'a pas accès au cookie via document.cookie.

Le drapeau secure précise que le cookie doit être transféré uniquement via le protocol HTTPS.

samesite précise que la requête doit provenir de notre propre site web et non d'une autre URL.

Babel

Utilité

Babel est un outil qui nous permet de convertir du code Javascript recent, et donc qui utilise les dernières fonctionnalités, dans un code utilisant une syntaxe plus ancienne et donc mieux supportés par les différents navigateur. Cela nous permet d'utiliser la dernière version de ECMAScript sans nous soucier du support du navigateur.

npm install --save-dev @babel/core @babel/cli

Pour installer et utiliser Babel, on suivra la documentation officielle

// Babel Input: ES2015 arrow function
[1, 2, 3].map(n => n + 1)

// Babel Output: ES5 equivalent
[1, 2, 3].map(function(n) {
  return n + 1;
});

Typescript

Définition

Typescript est un language de programmation qui peut remplacer le javascript. Typescript est un superset de javascript, ce qui veut dire que tout code javascript est valide en typescript cependant l'inverse n'est pas vrai.

Typescript permet de:

  • typer nos variables
  • typer nos signatures de fonction
  • d'avoir accès à de nouvelles fonctionnalités
  • profiter de features pas encore implémentés en JS
  • corriger des bugs avant meme que ces derniers arrivent

Typescript apporte une meilleur expérience développeur (DX)

Installation

Pour utiliser Typescript, il faudra avoir NodeJS installé sur notre machine.

npm install typescript --save-dev
npm install typescript --global

La premiere ligne installer Typescript uniquement dans un dossier donnée (sur un projet particulier).

La seconde installe Typescript globalement sur notre machine.

 

Le compilateur Typescript est nécessaire pour executer notre code Typescript.

⚠️ Typescript n'est pas utilisable directement depuis le navigateur!

Execution

On peut maintenant créer un fichier qui aura l'extension ".ts". Dans ce fichier on peut écrire du javascript et ce code sera valide.

Pour ensuite transpiler le code typescript en javascript, il faudra utiliser la commande:

tsc notreFichier.ts notreFichier.js
tsc notreFichier.ts

Le drapeau -w nous permet quant à lui d'observer et recompiler notre fichier dès que notre fichier Typescript sera modifié.

On peut aussi créer un fichier de configuration de Typescript grace a la commande:

tsc --init

Types

Lorsqu'on va déclarer une variable en Typescript, celle-ci va obtenir un type. Une fois un type déclarer, notre variable ne pourra plus changer de type:

let age: number = 42
age = "Autre" // Erreur

Voici une liste de différents type possibles:

let age: number = 42
let name: string = "Fabio"
let alive: boolean = true
let colors: string[] = ["red", "green", "blue"]
let someVariable: any
let someFunction: Function

const add = (x: number, y: number): number => {
  return x + y
}

Si aucun type n'est préciser, Typescript va alors inférer le type par lui-même.

Functions

Lorsqu'une fonction ne retourne rien on peut utiliser le mot clé void lors de la signature de la fonction:

const sayHello = (name: string): void => {
  console.log(`Hello ${name}`)
  // Cette fonction ne retourne rien
}

On peut préciser que certains paramètres de la fonction sont optionnels:

const sayHello = (name?: string): void => {
  if (name)
    console.log(`Hello ${name}`)
  else
    console.log('Hello stranger')
}

Union Types

Parfois, il peut être nécessaire d'avoir une variable acceptant deux types différents. On pourra donc utiliser les types Union comme suit:

const charactersStatus: (string | boolean)[] = ['Eddard Stark', false, 'Arya Stark', true]
// charactersStatus ne peut contenir que des strings et des boolean
let value: string | number | boolean = 'ok'
// value ne peut contenir qu'une string ou number ou boolean

On peut aussi créer un custom type (Type Aliases):

type StringOrNumber = string | number
let value: StringOrNumber = "string"
value = 0 // OK

Type Aliases

Il nous est aussi possible de créer un nouveau type:

type Player = {
  name: string
  level: number
  email?: string // optionnel
}

const newPlayer: Player = {
  name: 'SlothKing',
  level: 42,
}


const newPlayer: Player = {
  name: 'PrincessLeia',
  level: 58,
  email: 'naboo@resistance.sw',
}

Classes

Avec TypeScript, il est possible de définir clairement une propiété publique ou privée

class Position {
  private x = 47.5353423; // Ne sera pas accessible
  public y = 47.5353423; // Sera accessible via son instance
  readonly z = 0; // Non modifiable
}

Enums

Lorsqu'on connait toutes les possibilités d'un état, on peut stocker ces dernières dans un enum (pratique pour éviter des typo par exemple):

enum Direction {
  Up = 1,
  Down, // 2
  Left, // 3
  Right, // 4
}

const choosenDirection = Direction.Up

Interface

Une interface est comme un type alias sauf que celle-ci peut être implémentée par une classe, et peut être modifié pour ajouter des propriétés

interface Point {
  x: number;
  y: number;
  getPosition: () => [number, number];
}

class Position implements Point {
  x = 47.5353423;
  y = 47.5353423;
  getPosition() {
    return [x, y];
  }
}

Cheat Sheet

Vous pouvez retrouver des feuilles de rappel ici

RegEx

Definition

Une RegEx est une expression régulière (Regular Expression) qui peut avoir deux objectifs:

  • valider une chaine de caractères
  • rechercher une sous chaîne de caractères

En javascript, une RegEx est également un objet. En va pouvoir executer diverses méthodes sur une chaine de caractères afin de voir si cette dernière correspond à ce que l'on cherche.

Exemple d'une RegEx:

// Syntaxe conventionelle
const regex1 = /ab+c/;

// Avec la classe RegExp - prend plus de mémoire
const regex1 = new RegExp("ab+c");

mach - machAll

La méthode match retourne un tableau contenant les correspondances entre une string et une regex:

const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';

const array = [...str.matchAll(regexp)];

console.log(array[0]); //["test1", "e", "st1", "1"]

console.log(array[1]); // ["test2", "e", "st2", "2"]

La méthode matchAll  retourne un itérateur contenant l'ensemble des correspondances entre une chaîne de caractères d'une part et une expression rationnelle d'autre part

const paragraph = 'The quick brown fox jumps over the lazy dog. It barked.';
const regex = /[A-Z]/g;
const found = paragraph.match(regex);

search - replace/replaceAll

const paragraph = 'The quick brown fox jumps over the lazy dog. If the dog barked, was it really lazy?';
// any character that is not a word character or whitespace
const regex = /[^\w\s]/g;

console.log(paragraph.search(regex)); // 43

console.log(paragraph[paragraph.search(regex)]); // '.'

La méthode search retourne la position de la première correspondances entre une string et une regex:

const p = 'dog, dog, and dog';

console.log(p.replace('dog', 'monkey')); // monkey, dog, and dog

const regex = /Dog/i;
console.log(p.replace(regex, 'ferret')); // ferret, dog, and dog

const regex = /Dog/i;
console.log(p.replaceAll(regex, 'bird')); // bird, bird, and bird

La méthode replace retourne une nouvelle chaîne de caractères dans laquelle tout ou partie des correspondances à un modèle sont remplacées par un remplacement. replaceAll remplace toutes les occurences.

How-to?

// | -> OU logique
let regex = /dog|cat/g
// () -> Groupe de capture
regex = /nice(dog|cat)/g
// ? -> Le caractère précédent est valide 0 ou 1 fois
// * -> Le caractère précédent est valide 0 ou n fois
// + -> Le caractère précédent est valide 1 ou n fois
// {2,4} -> Le caractère précédent est valide 2 ou 4 fois
// \ -> sert a échapper un caractère special
// \d -> correspond à un chiffre
// \D -> correspond à ce qui n'est PAS un chiffre
// [A-Z] -> lettres de A à Z valides

La méthode search retourne la position de la première correspondances entre une string et une regex:

Le site regexr est très utile pour faire des tests et trouver la bonne combinaison de notre expression régulière. 

La méthode search retourne la position de la première correspondances entre une string et une regex:

Validation de champs

La Librairie Validator est très utile pour la validation de champs / chaînes de caractères, comme pour vérifier un email par exemple.

La librairie Joi propose de la validation de schéma, supporte les expressions régulières et possède de nombreuses méthodes, plus lisibles, permettant de valider un non un champs.

 

Yup est une alternative tout aussi interessante:

let schema = yup.object().shape({
  name: yup.string().required(),
  age: yup.number().required().positive().integer(),
  email: yup.string().email(),
  website: yup.string().url(),
  createdOn: yup.date().default(function () {
    return new Date();
  }),
});

Manipuler les dates

npm install dayjs

Manipuler les dates et faire des comparaisons entre elles peut être parfois délicat. Heureusement, des librairies comme Dayjs ou date-fns existent.

Pour l'installer sur un projet node, il faudra écrire dans le terminal:

<script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
<script>dayjs().format()</script>

Ou directement sur une page html via le CDN:

Dayjs présente l'avantage d'être très légère, rapide, avec une documentation claire, mise à jour très régulièrement, possible de travailler avec les dates locales, et compatible avec Typescript. 

Javascript - Advanced

By Fabio Ginja

Javascript - Advanced

Slides de formation - Juin 2022

  • 237