📘

La POO en JavaScript

Semblable à Java
 en plus souple.
⚠
Pour faire de la POO, on utilise maintenant TypeScript.

Créer des objets


Un objet est dĂ©clarĂ© avec des accolades, Ă  l’intĂ©rieur desquelles on dĂ©clare une liste de propriĂ©tĂ©s qui sont des paires nom:valeur.

On accÚde à la clé avec le point (BP) ou les crochets.

Les objets sont dynamiques : pas de new, ajout de propriĂ©tĂ©s simplifiĂ© —> cela demande une certaine rigueur pour ne pas faire n’importe quoi !

let uneFleur = {nom:"tulipe", couleur:"jaune"};
console.log(uneFleur); //{ nom: 'tulipe', couleur: 'jaune' }
console.log(uneFleur.nom + " === " + uneFleur["nom"]); //tulipe === tulipe
uneFleur.couleur="orange"; //orange
console.log(uneFleur.couleur);

Il est possible de faire des tableaux d’objets, mĂȘme des tableaux de tableaux d’objets


—> notation JSON.

📌
Pour aller plus loin : - sur les objets en JavaScript https://www.w3schools.com/js/js_objects.asp - sur JSON https://la-cascade.io/articles/json-pour-les-debutants https://developer.mozilla.org/fr/docs/Learn/JavaScript/Objects/JSON

Créer des classes


1. façon traditionnelle

Une classe se déclare avec let (comme une variable) et le mot-clé function : elle prend entre zéro et plusieurs paramÚtres, des attributs et des éventuelles fonctions.

Une instance se crée avec le mot-clé new et en renseignant les valeurs des différents paramÚtres.

let UneClasseALancienne = function (unParam, autreParam) {
    this.unParam = unParam;
    this.autreParam = autreParam;
    this.uneFonction =  function () {
        console.log("Je suis une fonction de classe.");
    }
}

let uneInstance = new UneClasseALancienne("une chaine de caractĂšres", 42);
console.log(uneInstance);
/*
	UneClasseALancienne {
	  unParam: 'une chaine de caractĂšres',
	  autreParam: 42,
	  uneFonction: [Function (anonymous)]
	}
*/
console.log(uneInstance.uneFonction()); //Je suis une fonction de classe.

â„č
Classe vs Objet : - un objet peut ĂȘtre modifiĂ© Ă  la volĂ©e, il est facile Ă  manipuler et Ă  utiliser - une classe permet de structurer le code et amĂ©liore la maintenabilitĂ©, notamment utile en SPA (single page application) BP : sur un gros projet, il est prĂ©fĂ©rable de passer par des classes.

2. Nouvelle façon (TypeScript)

Une classe se déclare avec le mot-clé class, elle possÚde un constructeur auquel on passe des paramÚtres et au sein duquel on déclare les attributs, elle possÚde également des méthodes.

Comme en Java, mais simplifié  On passe en fait par le tsc, compiler du TypeScript.
class UneClasse {
    constructor(unParam, autreParam) {
        this.unParam = unParam;
        this.autreParam = autreParam;
    }
    uneFonction() {
        console.log("Je suis une fonction de classe.");
    }
}
let uneNouvelleInstance = new UneClasse("une chaine de caractĂšres", 42);
console.log(uneNouvelleInstance); //UneClasse { unParam: 'une chaine de caractĂšres', autreParam: 42 }
console.log(uneNouvelleInstance.uneFonction()); //Je suis une fonction de classe.

Héritage


Une classe hérite des attributs et méthodes du parent.

BP : prĂ©fĂ©rer l’utilisation de class et extends.

(+) Notion de prototype

Notion qui me reste hermétique
 et qui est désuÚte.

Un prototype est la structure || forme que doit respecter la classe enfant et permet l’hĂ©ritage des fonctions parent avec ClasseEnfant.prototype = Object.create(ClasseParent.prototype);.

Il est ensuite possible de substituer les fonctions avec ClasseEnfant.prototype.fonctionASubstituer = ...

⚠
La substitution d’une fonction Ă  ce stage sous-entend que la classe a juste Ă©tĂ© mal prĂ©vue au dĂ©but


Librairies


Un fichier JavaScript peut ĂȘtre considĂ©rĂ© comme une libraire (ex : jQuery).

⚠
Lors de l’appel de plusieurs scripts JavaScript (ou librairies) dans un fichier HTML, le plus bas dans le script est interprĂ©tĂ© en dernier —> attention Ă  l’ordre !

Contexte d’exĂ©cution

Quand on a diffĂ©rentes librairies, on veut avoir des contextes (ou cadres) d’exĂ©cution.

On utilise des fonctions anonymes, déclarées avec let uneFonctionAnonyme = function(params) { instructions } et appelées simplement avec uneFonctionAnonyme(valeurs);.

Une autre façon de dĂ©clarer une fonction anonyme est d’enlever le let et de l’encapsuler entre parenthĂšses : (function(param) { instructions }) ();.

BP : c’est mieux d’encapsuler la fonction anonyme car elle n’est pas enregistrĂ©e (elle n’a pas de nom), ce qui permet un gain de performance.

Il est possible de les déclarer et de les appeler immédiatement : fonctions anonymes immédiatement invoquées. La fonction est encapsulée dans des parenthÚses, on renseigne la valeur des paramÚtres juste aprÚs : (function(param) { instructions }) (valeurs);

â„č
L’encapsulation permet de protĂ©ger les traitements.

On utilise Ă©galement des fonctions flĂ©chĂ©es qui diffĂšrent des fonctions anonymes car elles n’utilisent pas le mot-clĂ© function. Il s’agit d’une simplification de la syntaxe de dĂ©claration dans laquelle les paramĂštres sont entre parenthĂšses (qui restent vides s’il n’y a pas de paramĂštres), suivis d’une flĂšche => et des instructions entre accolades. Lors de l’appel, les instructions sont Ă©valuĂ©es et le rĂ©sultat est retournĂ© : let uneFonctionFlechee = () => { instructions };.

En Java, cela équivaut aux fonctions lambda.
let fonctionAnonyme = function(param) {
    console.log("Je suis une fonction anonyme !");
}

let fonctionInvoquee = (
	function(param) {
    console.log("Je suis immédiatement invoquée !");
})("un paramĂštre");

(() => {
    console.log("Je suis aussi une fonction invoquée, mais fléchée !");
})();

(+) Notion de closure

Désuet


Spécialisation de méthodes :

via prototype possible mais verbeux et statique

via une fonction contextualisée (une closure) qui permet de retourner une fonction encapsulée (protégée du code)

exemple avec un compteur : on utilise une fonction anonyme automatiquement invoquĂ©e qui let un compteur et qui retourne une fonction anonyme dans laquelle j’incrĂ©mente le compteur et retourne le compter

—> donc le let est immĂ©diatement invoquĂ© lorsque le script est interprĂ©tĂ© (quand il passe sur la ligne) et ensuite quand on appelle la fonction, y a que le return qui est exĂ©cutĂ© (ça incrĂ©mente le compteur et il est hors de portĂ©e si on passe par la fonction)

(+) pattern factory par closure

Stockage local


Deux variables sont disponibles pour sauvegarder des choses dans le navigateur, qui disparaissent lorsque le cache est supprimé : LocalStorage et SessionStorage, avec des méthodes associées comme setItem(cle,valeur), geItem(cle), removeItem(cle), clear().

object = { name: "Bob", age: 42 };

// sauvegarder un tableau, prealablement transforme en string
localStorage.setItem("oneObject", JSON.stringify(object));

// recuperer ce tableau
object = JSON.parse(localStorage.getItem("key"));

console.log(object);
â„č
La mĂ©thode JSON.stringify() permet de transformer un objet JSON en string. L’inverse se fait avec la mĂ©thode JSON.parse(). —> Souvent utilisĂ© pour les Ă©changes de donnĂ©es depuis et vers un serveur web, puisqu’il faut que la donnĂ©e soit une string pour ĂȘtre envoyĂ©e Ă  un serveur web.

Traitements asynchrones


On parle de “synchrone” lorsque les traitements sont effectuĂ©s les uns aprĂšs les autres et d’”asynchrone” lorsqu’ils sont effectuĂ©s en parallĂšle.

Les traitements asynchrones permettent de laisser des traitements un peu longs se faire et récupérer le résultat plus tard, ce qui donne des applications plus réactives.

â„č
CĂŽtĂ© front, il n’est pas possible de multi-threader.

Option 1 : les callbacks

DĂ©suet
 RĂ©volution Ă  l’époque, maintenant on utilise des observables et des promesses.

“CapacitĂ© de passer une fonction Ă  une autre fonction et s‘assurer que cette fonction peut ĂȘtre appelĂ©e dans notre fonction”.

Le mot-clĂ© callback est passĂ© en paramĂštre d’une fonction A lors de sa dĂ©claration. Lors de l’appel de cette fonction A, une fonction B est passĂ©e pour le paramĂštre callback.

Exemple d’utilisation : mettre Ă  jour une information sur un site (nombre de visiteurs, compteurs
) grĂące aux mĂ©thodes setTimeout() ou setInterval() utilisĂ©es comme callbacks.

// Exemple d'Alain Cariou
//  les méthodes direHello() et direHaha() sont passés en tant que callback 
//  à la méthode repeter
function direHello() {
    console.log("Hello World !");
}

function direHaha() {
    console.log("Haha !")
}

function repeter(callback) {
    setInterval(function() {
        callback()
    }, 1000);
}

repeter(direHello);
console.log("AprÚs répéter");
repeter(direHaha);

Option 2 : les promesses (trĂšs actuel)

“MĂ©canisme qui permet de faire un traitement de maniĂšre asynchrone”.

Il fonctionne avec un objet Promise qui prend en paramĂštre une fonction, qui elle-mĂȘme prends deux paramĂštres (resolve si la promesse est un succĂšs et reject en cas d’erreur).

Pour l’exĂ©cuter, on l’appelle et on rĂ©cupĂšre le rĂ©sultat avec .then. On peut utiliser un . catch.

Exemple de traitement : interroger une API.

// Exemple d'Alain Cariou
function getData() {
    return new Promise((resolve, reject) => {
        console.log("Début promesse !");
        resolve({"ok": "Tout s'est bien passé !"});

        // setTimeout(() => {
        //     resolve({"ok": "Tout s'est bien passé !"});
        //     reject(new Error("Echec de la promesse !"));
        // }, 2000);
    });
}

let result;
console.log("I - Je fais des trucs.");
getData().then((data) => {
    result = data;
    console.log("II - Récupération des données : " + data);
}).catch((error) => {
    console.log(error);
});
result = getData();
console.log("III - Je fais d'autres trucs !");
console.log(result);
📌
Pour aller plus loin : https://guide-angular.wishtack.io/angular/callback-hell-vs.-promise-vs.-async-await/promise

(+) les observables

Hors programme.

On peut chaĂźner les uns aux autres, on s’y subscribe (le flux de donnĂ©es peut continuer Ă  arriver) ≠ promesse qui est juste une action qui commence et se termine.