// BLOG

Quick JavaScript

Je vais suivre une formation de 3 mois chez O'Clock intitulé "Socle Fullstack javaScript" afin d'acquérir les bases de JavaScript et de son ecosystème. En attendant la formation qui débutera début juin 2020, je redige ce petit pense-bête pour avoir sous la main rapidement les structures de base du langage.

Rédigé le 19.02.2020
Par Gilles Vauvarin

JavaScript

Je vais suivre une formation de 3 mois chez O'Clock intitulé "Socle Fullstack javaScript" afin d'acquérir les bases de JavaScript et de son ecosystème. En attendant la formation qui débutera début juin 2020, je redige ce petit pense-bête pour avoir sous la main rapidement les structures de base du langage.

Ce pense-bête est un résumé ultra condensé du cours javaScript de Pierre Giraud que je vous encourage vivement à consulter si vous souhaitez aller plus en profondeur dans les explications. Des extraits sont également issus de la documentation du site Mozilla.

Si vous préférez le strict minimum concernant le langage JavaScript, vous pouvez essayez les cheat sheet.

Variable et Constante

Eviter l'utilisation de "var" qui est plus permissif que "let" et sera à terme déprécié.

// variable
let myVar;
myVar = "Hello word";

// on peut déclarer plusieurs variables sur la même ligne
let a = 1, b = 2;

// constante, 
// elle doit être obligatoirement affectée d'une valeur lors de sa déclaration
const myConst = 3.14;

Opérateurs

Opérateurs arithmétiques

Opérateur Fonction
+ Addition
- Soustraction
* Multiplication
/ Division
% Modulo (reste d’une division euclidienne)
** Exponentielle (élévation à la puissance d’un nombre par un autre)
+= Additionne puis affecte le résultat
-= Soustrait puis affecte le résultat
*= Multiplie puis affecte le résultat
/= Divise puis affecte le résultat
%= Calcule le modulo puis affecte le résultat

Exemples :

// x stocke 4
let x = 4; 

/*
* On ajoute 3 à la valeur stockée précédemment par x (4) puis on
* affecte le résultat à x. x stocke désormais 4 + 3 = 7
*/
x += 3;

Opérateurs logiques et de comparaison

Opérateur Fonction
== Permet de tester l’égalité sur les valeurs
=== Permet de tester l’égalité en termes de valeurs et de types
!= Permet de tester la différence en valeurs
<> Permet également de tester la différence en valeurs
!== Permet de tester la différence en valeurs ou en types
< Permet de tester si une valeur est strictement inférieure à une autre
> Permet de tester si une valeur est strictement supérieure à une autre
<= Permet de tester si une valeur est inférieure ou égale à une autre
>= Permet de tester si une valeur est supérieure ou égale à une autre
AND ou && Renvoie "true" si tout les éléments sont "true"
OR ou || Renvoie "true" si au moins un élément est "true"

Exemples :

let x = 12;

// renvoie "true" ET l'affecte à la variable "maVariable"
let maVariable = x == 12;

Opérateurs d'incrémentation et décrémentation

Opérateur Fonction
++x Pré-incrémentation : incrémente la valeur contenue dans la variable x, puis retourne la valeur incrémentée
x++ Post-incrémentation : retourne la valeur contenue dans x avant incrémentation, puis incrémente la valeur de x
--x Pré-décrémentation : décrémente la valeur contenue dans la variable x, puis retourne la valeur décrémentée
x-- Post-décrémentation : retourne la valeur contenue dans x avant décrémentation, puis décrémente la valeur de x

Exemples :

let x = 2;

// y contient "3"
let y = ++x;

// y contient "2"
let y = x++;
// z contient "3"
let z = x;

Concaténation et les littéraux de gabarits

La concaténation de chaînes de caractères se fait à l'aide du signe "+" si au moins une des opérandes est de type String. Si toutes les opérandes sont de type Number, JavaScript les additionne de façon arithmétique.

let v = ' Samanta'; // on peut aussi utiliser des guillemets doubles "" ou des backticks ``
let w = 7 + 4; // Le signe "+" est ici un opérateur arithmétique
let x = 'Hello';
let y = w + ' word'; // Le signe "+" est ici un opérateur de concaténation
let z = x + v // Le signe "+" est ici un opérateur de concaténation

Avec les guillemets simples et doubles, il faut utiliser un caractère d'échapement "\" pour les apostrophes ou guillemets doubles dans le texte.

// échapement de l'apostrophe
let phrase = 'Nous vivons un drôle d\'époque';

// ajout d'un retour à la ligne
let retourLigne = 'Bonjour Mr le Renard,
\n que vous me semblez beau';

Utilisation des backticks et des littéreaux de gabarits

let x = 3;
let y = 4;

// ici pas besoin de caractères d'échapement ou de retour à la ligne \n
let mesBackticks = `J'ai ${x} pommes
      et ${y} poires
      J'ai au total ${x + y} fruits`

Instructions conditionnelles

if …, if … else, if … elseif … else

let x = 4;
let resultat;

// if ...
if ( x == 4 ) { 
    resultat = 'Le résultat est vrai';
}

// if ... else ...
if ( x == 4 ) { 
    resultat = 'Le résultat est vrai';
} else {
    resultat = 'Le résultat est faux';
}

// if ... elseif ... else ...
if ( x == 4 ) { 
    resultat = 'Le résultat est vrai';
} elseif ( x != 4 ) {
    resultat = 'Le résultat est faux';
} else {
    resultat = 'Le résultat est ni vrai ni faux';
}

Opérateur ternaire (même chose que if… else… mais en version plus compacte)

let x = 4;
let monResultat;

// variable = (affectation) condition ? (résultat si vrai) : (résultat si faux) 
monResultat = x == 4 ? 'Le résultat est vrai' : 'Le résultat est faux';

// ici monResultat contient 'Le résultat est vrai' car la condition est vrai

Instruction switch … case

L’instruction switch … case permet d’exécuter différentes portions de codes en fonction de la valeur d’une variable.

let x = 4;

switch( x ) {
    case 1:
        document.write() = 'x contient 1';
        break;
    case 2:
        document.write() = 'x contient 2';
        break;
    case 3:
        document.write() = 'x contient 3';
        break;
    case 4:
        document.write() = 'x contient 15';
        break;
    case 5:
        document.write() = 'x contient 20';
        break;
    default:
        document.write() = 'x contient aucun des nombres 1,2,3,4,5';
}

Les boucles for

Les boucles permettent d'exécuter un code « en boucle » tant qu’une condition donnée est vraie. Par exemple lire les valeurs d'un tableau tant qu'il y a des valeurs dans ce tableau. Il faudra veiller à ce que la condition soit fausse à un moment donné pour sortir de la boucle.

for …

Passe en boucle un bloc de code tant que le test est vrai.

// on initialise i à 0 
// on test que i est bien strictement inférieur à 10 
// si test ok, on incrémente i de +1 et on execute le code
// puis on revient au début de la boucle pour voir si le test est toujours ok

for ( let i = 0; i < 10; i++ ) {
    // ... code
}

// Ex: parcourir un tableau
a[ 1, 2, 3, 4 ];
let sum = 0;
for ( var i = 0; i < a.length; i++ ) {
    sum + = a[i];
}

for … in

Boucle à travers les propriétés d'un objet (Array, Object). L'incrémentation se fait automatiquement pour nous et démarre à "0".

var person = {
fname:"John", 
lname:"Doe", 
age:25
};

var text = "";
var x;
for ( x in person ) {
  text += person[x] + " ";
} 

// affiche :
// John Doe 25

for … of

Boucle à travers les valeurs d'un objet itérable. Pour les cas où l'indice précis d'un élément n'est pas nécessaire pendant l'itération, vous pouvez utiliser la boucle forof.

// exemple avec un tableau :
var cars = ['BMW', 'Volvo', 'Mini'];
var x;

for ( x of cars ) {
  document.write( x + "<br>" );
} 

// affiche :
// BMW
// Volvo
// Mini

// exemple avec un objet :
const passengers = [
    {
        name: "Will Alexander",
        ticketNumber: 209542
    },
    {
        name: "Sarah Kate",
        ticketNumber: 169336
    },
    {
        name: "Audrey Simon",
        ticketNumber: 779042
    },
    {
        name: "Tao Perkington",
        ticketNumber: 703911
    }
]

for ( let passenger of passengers ) {
    console.log( 'Embarquement du passager ' + passenger.name + ' avec le ticket numéro ' + passenger.ticketNumber );
}

Les boucles while

while …

Execute un code tant que la condition est vraie.

var text = "";
var i = 0;

// boucle sur le code tant que i est strictement inférieur à 5
while ( i < 5 ) {
  text += "<br>The number is " + i;
  i++;
} 

// affiche :
// The number is 0
// The number is 1
// The number is 2
// The number is 3
// The number is 4

do … while

La condition est évaluée après l'exécution du code, ce qui fait que le code spécifiée s'exécute au moins une fois.

let result = "";
let i = 0;

do {
  i = i + 1;
  result = result + i;
} while ( i < 5 );

console.log( result );
// la console renvoie: "12345"

Instruction continue et break

continue

Pour sauter une itération de boucle et passer directement à la suivante, on peut utiliser une instruction continue.

for ( let i = 0; i < 10; i++ ) {
    // Si i/2 possède un reste, alors i est impair
    if ( i % 2 != 0 ) {
        continue;
    }
    document.write( i );
}

// affiche : 0 2 4 6 8

break

Cette instruction permet de sortir d'une boucle.

for ( let i = 0; i < 1000; i++ ) {
    // On sort de la boucle dès que la valeur de i atteint 13
    if ( i == 13 ) {
        break;
    }
    code à executer dans la boucle ...
}

Les fonctions

Une fonction est une séquence de code nommé et réutilisable à laquelle on peut passer des arguments et qui renvoie une valeur (ou pas).

Fonctions prédéfinies

JavaScript mets à notre disposition un certain nombre de fonctions prédéfinies (plus exactement des méthodes d'objets) qui effectuent des tâches complexes sans qu'on ait à en définir le code.

Les fonctions prédéfinies peuvent avoir aucun argument, 1 argument ou plusieurs arguments. Ceux-ci peuvent être optionels ou obligatoires.

Voir la documentation en ligne.

Fonctions personnalisées

Il faut définir une fonction personnalisée lorsque que l'on répète une même tâche plusieurs fois dans son code.

Faire en sorte que la fonction ne fasse qu'une seule tâche à la fois et qu'elle soit la plus simple possible.

// déclaration d'une fonction
function maSuperFonctionAddition( a , b ) {
    return a + b;
}

// ou ...

let maSuperFonctionAddition = function( a , b ) {
    return a + b;
}

// utilisation de la fonction
let x = maSuperFonctionAddition( 2 , 3 );

// x contient 5

return permet à la fonction de retourner une valeur et de stopper son exécution.

Fonctions anonymes

Une fonction anonyme est une fonction définie sans nom. On les utilisent lorsque l'on a besoin d'utiliser une fonction qui ne sera ni rappelée ni réutilisée ailleurs dans notre code.

function( element ) {
    return element * 2;
}

Usage fréquent des fonctions anonymes :

- Affectation d'une fonction anonyme à une variable afin de pouvoir l'appeler par la suite.

- Fourniture d'une fonction anonyme en tant que paramètre à une autre fonction.

- Renvoi d'une fonction anonyme à partir d'une autre fonction.

Pour executer une fonction anonyme on peut :

- Enfermer le code de notre fonction dans une variable et utiliser la variable comme une fonction.

- Auto-invoquer notre fonction anonyme.

- Utiliser un évènement (ex: onclick) pour déclencher l’exécution de notre fonction.

Expression de fonctions

On peut directement assigner une fonction à une variable et utiliser la fonction via la variable.

let helloWord = function() {
    document.write( 'Hello Word!' );
};

// ou ...

let helloWord = function hello( name ) {
    document.write( 'Hello ' + name );
};

// utilisation de la fonction via la variable
helloWord();

Fonctions auto-invoquées

La deuxième façon d’exécuter une fonction anonyme va être de créer une fonction anonyme qui va s’auto-invoquer (= s'auto-exécuter). Dans ce cas, la fonction anonyme s'exécute dès sa création.

Pour cela, on ajoute des parenthèses autour de la fonction de la façon suivante :

// fonction anonyme auto-invoquée
( function() { alert('Hello') } )();

// fonction nommée auto-invoquée
( function hello() { alert('Hello') } )();

Une fonction nommée auto-invoquée n'a pas trop d'intérêt sachant que la fonction peut être exécutée à l'aide de son propre nom. Par contre pour une fonction anonyme, cela a tout son sens.

Fonctions récursives

Une fonction récursive est une fonction qui va s’appeler elle-même au sein de son propre code.

Tout comme pour les boucles, les fonctions récursives vont nous permettre d’exécuter une action en boucle jusqu’à ce qu’une certaine condition de sortie soit vérifiée.

// approche avec une boucle
function countDownFrom(number) {
    for ( let i = number; i > 0; i-- ) {
	console.log(i);
    }	
}

countDownFrom(5);
// 5
// 4
// 3
// 2
// 1


// approche récursive
function countDownFrom(number) {
    if ( number === 0 ) {
	return; // ce test permet de sortir de la recursion
    }
    console.log( number );    
    countDownFrom( number - 1 );
}

countDownFrom(5);
// 5
// 4
// 3
// 2
// 1

Fonctions fléchées

Il s'agit d'une écriture condensée des fonctions. Elles ont été faites pour être déclarées sur une seule et unique ligne, si ce n'est pas le cas, les accolades et le mot return sont requis. Attention, les fonctions fléchées ne possèdent pas de valeur pour this ni pour l’objet arguments.

// déclaration classique
let addition = function( a, b ) {
    return a + b;
};

// équivalent en fonction fléchée :
let addition = (a, b) => a + b;

// le mot "function" est omis, 
// les accolades sont remplacées par une grosse flèche, 
// le mot "return" est omis

// si la fonction possède qu'un seul argument, les parenthèses disparaissent
// déclaration classique :
let double = function( n ) {
    return n * 2
}

// équivalent en fonction fléchée :
let double = n => n * 2;

Portée des variables

- Une variable globale, déclarée en dehors d'une fonction, est visible et manipulable dans l'ensemble du script d'une page y compris des fonctions.

- Une variable locale, déclarée à l'intérieur d'une fonction, n'est visible et manipulable qu'à l'intérieur de cette fonction. Les paramètres d'une fonction sont également des variables locales.

Une bonne pratique est d'éviter d'utiliser le même nom pour une variable locale et une variable globale même si cela est possible en javaScript.

Différences de portée entre les variables var et let

Attention, il existe une différence de portée entre les deux types de déclaration qu’on va pouvoir observer lors de la définition de variables locales. En effet, lorsqu’on utilise la syntaxe let pour définir une variable à l’intérieur d’une fonction en JavaScript, la variable va avoir une portée dite « de bloc » : la variable sera accessible dans le bloc dans lequel elle a été définie et dans les blocs que le bloc contient. Un bloc est défini par des accolades ouvrantes et fermantes.

En revanche, en définissant une variable avec le mot clef var dans une fonction, la variable aura une portée élargie puisque cette variable sera accessible dans tous les blocs de la fonction.

Programmation orientée objet

La POO permet un code plus modulaire, flexible ainsi qu’une meilleure lisibilité et maintenabilité qu'un code procédural.

Un objet est un conteneur qui possède une collection de clé : valeur que l'on appelle des propriétés.

Une propriété peut avoir comme valeur une fonction (on parle alors de méthodes), un tableau, un objet ou tout autre type de donnée primitive (Integer, String, Boolean …)

Nativement, javaScript utilise et met à disposition un certain nombre d'objets prédéfinis qu’on va pouvoir directement utiliser. Mais il est également possible de créer ses propres objets.

Il y a 5 manières de créer des objets en javaScript :

- Créer un objet littéral

- Utiliser le constructeur Object()

- Utiliser une fonction constructeur personnalisée

- Utiliser la méthode create()

- Utiliser les mots clés class et new

Nous utiliserons le plus souvent la dernière manière avec les mots clés class et new introduite par ES6.

Créer un objet littéral

On créer un objet littéral en initialisant une variable qui contiendra une valeur de type Object et à l'aide d'accolades qui englobent les membres nom : valeur , de l'objet. Ces membres peuvent être des propriétés de n'importe quel type. Chacune des propriétés et des méthodes est ici créé littéralement d'où le nom d'objet littéral.

let voiture = {
    nom : ['Volvo', 'XLK'],
    annee : 2017,
    carburant : 'diesel',
    afficherInfo: function() {
        alert( 'Je suis de la marque ' + this.nom[0] + ', j\'ai été construite en ' + this.annee + ' et je roule au ' + this.carburant);
    }
};

// on pourrait également définir les propriétés et les méthodes à posteriori

let voiture = {};

voiture.nom = ['Volvo', 'XLK'];
voiture.annee = 2017;
voiture.carburat = 'diesel';
voiture.afficherInfo = function() {
        alert( 'Je suis de la marque ' + this.nom[0] + ', j\'ai été construite en ' + this.annee + ' et je roule au ' + this.carburant);
    };

Si je veux créer un deuxième objet "voiture" je devrais déclarer une nouvelle variable "voiture_2" et lui affecter de façon littérale des nouvelles valeurs à ses propriétés.

Les propriétés et les méthodes d'un objet sont accessibles par la notation pointée (accesseur point) :

voiture.nom[0]; // Volvo
voiture.annee; // 2017
voiture.afficherInfo() // Je suis de la marque Volvo, j'ai été construite en 2017 ...

De la même manière, on peut modifier/ajouter une propriété ou une méthode à notre objet :

// modifier l'année de construction
voiture.annee = 2019;

// ajouter une propriété "couleur" à l'objet voiture
voiture.couleur = 'violet métalisé";

// ajout d'une méthode afficherCouleur()
voiture.afficherCouleur = function(){
    alert( 'Ma couleur est ' + this.couleur );
}

Les propriétés peuvent également être accessibles à l'aide d'une notation par crochets (un peu comme des tableaux littéraux) :

voiture['nom'][0]; // Volvo
voiture['annee']; // 2017
voiture['afficherCouleur'](); // Ma couleur est violet métalisé

La notation crochet est plus complexe mais plus fléxible et permet des synthaxes que la notation pointée ne permet pas.

// la clé est une chaine de caractère avec espace
"immatriculation du véhicule" : "3345FV54";
voiture.["immatriculation du véhicule"]; // 3345FV54

// la clé est une expression javaScript (une variable ...)
let immatriculation = "3345FV54";
voiture.[immatriculation]; // 3345FV54

On peut également supprimer une propriété d'un objet via le mot clé delete.

delete voiture.immatriculation;

Le mot clé this

this fait référence à l'objet en cours et que l'on est en train de manipuler, ici "voiture". Nous verrons davantage son utilité lorsque nous aurons besoin de créer des objets à la chaine de façon dynamique en utilisant par exemple un constructeur.

Créer un objet en utilisant Object()

// création d'un objet vide
let human = new Object();

// ajout de propriétés et méthodes
human.age = 16;
human.name = "Anatoline";
human.displayHello = function() { return "<div>" + Hello word + "</div>"; }

Créer un objet en utilisant une fonction constructeur personnalisée

Si on a besoin de créer à la chaine des objets semblables partageant la même structure (propriétés et méthodes), plutôt que de créer les objets un à un de manière littérale, nous allons utiliser un constructeur d’objets qui n’est autre qu’une fonction constructeur.

Une fonction constructeur d’objets est une fonction qui va nous permettre de créer des objets semblables. Comme pour les fonctions classiques, il faut d'abord définir la fonction constructeur puis ensuite nous allons appeler ce constructeur à l'aide du mot clé new pour créer (instancier) nos objets.

Dans une fonction constructeur, on définit des propriétés et de méthodes. Les objets créés à partir de ce constructeur (instance) via le mot clé new hériteront des propriétés et des méthodes définies dans le constructeur. Par convention, le nom de la fonction commencera par une majuscule.

// définition de la fonction constructeur
function Voiture( nom, annee, carburant ) {
    this.nom = nom;
    this.annee = annee;
    this.carburant = carburant;
    this.afficherInfo = function() {
        alert( 'Je suis de la marque ' + this.nom[0] + ', j\'ai été construite en ' + this.annee + ' et je roule au ' + this.carburant);
    }
};

// création d'un objet à partir de la fonction constructeur
let maVoiture = new Voiture( ['Austin Mini', 'Countryman'], '2020', 'Essence' );

// appel d'une méthode
maVoiture.afficherInfo();
Attention ! l'utilisation des fonctions constructeur nécessite une bonne compréhension des prototypes pour optimiser l'utilisation de l'espace mémoire occupé par les objets. Utilisez la nouvelle synthaxe avec class et new si vous souhaitez laisser JavaScript gérer une utilisation optimum des prototypes.

En JavaScript, une fois une instance créée on peut à tout moment modifier/ajouter/supprimer dynamiquement ses propriétés ou méthodes.

Créer un objet en utilisant la méthode create()

La méthode create() permet de créer un objet en spécifiant un prototype comme premier argument. L'objet nouvellement créé héritera des toutes les propriétés du prototype passé en paramètre de la méthode create().

const animal = {};

// l'objet "dog" nouvellement créé héritera de toutes les propriétés de l'objet prototyope "animal".
const dog = Object.create( animal );

La méthode create() peut prendre un second paramètres qui est un objet d'objets, afin d'ajouter des propriétés manquantes au prototype.

const animal = {};

const dog = Object.create( animal, {
  breed: {
    value: 'Siberian Husky'
  }
} );
console.log( dog.breed ); //affiche 'Siberian Husky'

Créer un objet en utilisant les mots clés class et new

ES6 a introduit la synthaxe avec les mots clés class et new. Cette dernière permet de se rapprocher de la synthaxe objet des autres langages basés sur les classes. Cependant, JavaScript reste basé sur l'utilisation des prototypes en arrière-plan.

// définission de la classe
class Animal {
  constructor( nom, sexe, age ) {
    this.nom = nom;
    this.sexe = sexe;
    this.age = age;
    this.male = 'Mâle';
    this.femelle = 'Femelle';
  }
  display() {
      let genre = this.sexe == 'F' ? this.femelle : this.male;
      return "<div>" + this.nom + "-" + genre + "-" + this.age + "</div>";
  }
}

// création de l'objet par instanciation de la classe
let chat = new Animal( 'kity', 'F', '3' );

chat.display();
// affiche : kity-Femelle-3

Lorsque l'on instancie la classe Animal à l'aide du mot clé new , on applle la méthode constructor de la classe. Celle-ci alimente les valeurs des propriétés de l'objet (accesibles à l'aide de this) à l'aide des valeurs passées en paramètres lors de l'instanciation.

Les propriétés et les méthodes d'une classe peuvent être privées. Dans ce cas, elles ne sont accessibles qu'à l'intérieur de la classe et non de l'extérieur. Depuis ECMAScript2019, le caractère # permet d'indiquer qu'une propriété ou une méthode est privée.

// définission de la classe
class Animal {
  #mal; // propriété privée
  #femalle; // propriété privée
  constructor( nom, sexe, age ) {
    this.nom = nom;
    this.sexe = sexe;
    this.age = age;
    this.#male = 'Mâle';
    this.#femelle = 'Femelle';
  }
  display() { // ne pas oublier le # quand on fait référence à une propriété privée
      let genre = this.sexe == 'F' ? this.#femelle : this.#male;
      return "<div>" + this.nom + "-" + genre + "-" + this.age + "</div>";
  }
}

// création de l'objet par instanciation de la classe
let chat = new Animal( 'kity', 'F', '3' );

chat.display();
// affiche : kity-Femelle-3

Pour conserver l'intégrité des données (encapsulation), il est usel de créer des méthodes accesseurs (setter et getter) afin de récupérer ou modifier les propriétés.

En JavaScript, il existe un mot clé set et get pour définir ces accesseurs mais attention, il vont se comporter ensuite comme des propriétés dans leur utilisation.

// définission de la classe
class Animal {
  nom;

  constructor( nom ) {
    this.nom = nom;
  }

  get nomValue() {
      return this.nom;
  }

  set nomValue( newNom ) {
       this.nom = newNom;
       return this.nom;
  } 

}

// création de l'objet par instanciation de la classe
let chat = new Animal( 'kity');

chat.nomValue; // notation pointée comme pour appeler une propriété
// affiche : kity

chat.nomValue = 'Piffou';  // s'utilise comme une propriété
chat.nomValue;
// affiche : Piffou

Propriétés et méthodes static

Les méthodes et propriétés statiques appartiennent à la classe et non à l'instance de cette classe. Ainsi, une instance n'est pas nécessaire pour appeler la propriété/méthode statique, elle est appelée directement sur la classe.

class Article {
  constructor( titre, description ) {
    this.titre = titre;
    this.description = description;
  }
  static publisher = "Agnes Dumont";  // la propriété static n'est pas dans un constructeur
  static publisherUppercase() {
    console.log( this.publisher.toUpperCase() );
  }
}

console.log( Article.publisher ); // Agnes Dumont
Article.publisherUppercase(); // AGNES DUMONT

L'héritage en JavaScript

L'héritage consiste à créer un objet enfant à partir d'un objet parent afin que l'objet enfant hérite de toutes les propriétés et méthodes de l'objet parent.

Pour étendre une classe, nous utiliserons les mots clés extends et super

// classe parent
class Utilisateur {
  constructor( nom, email ) {
    this.nom = nom;
    this.email = email;
  }
  displayName() {
    return "<div>" + this.nom + "</div>";
  }
}

// classe enfant qui hérite de la classe parent ci-dessus
class Administrator extends Utilisateur {
  constructor( nom, email, website ) {
    super( nom, email ); // appelle le constructeur parent
    this.website = website;
  }
  displayEmail() {
    return "<div>" + this.email + "</div>";
  }
}

let jessica = new Administrator( 'Jessica Born', 'jb@gmail.com', 'https://jb.com' );
jessica.displayName(); // Jessica Born
jessica.displayEmail(); // jb@gmail.com

A noter qu'à droite du mot clé extends on peut aussi mettre une expression javaScript comme une fonction.

Surcharger une méthode

Si dans la classe enfant, lors de l'héritage, une méthode porte le même nom qu'une méthode de la classe parente, la méthode enfant écrase (surcharge) la méthode parent.

Si on veut utiliser le code d'une méthode parent et étendre son code, on invoque dans la classe enfant, la méthode parent avec le mot clé super à l'intérieur d'une méthode portant le même nom que la classe parent à surcharger, puis on étend le code de celle-ci.

// classe parent
class Utilisateur {
  constructor( nom, email ) {
    this.nom = nom;
    this.email = email;
  }
  displayName() {
    alert( `${this.nom}` );
  }
}

// classe enfant qui hérite de la classe parent ci-dessus
// écraser la méthode displayName
class Administrator extends Utilisateur {
  constructor( nom, email, website ) {
    super( nom, email ); // appelle le constructeur parent
    this.website = website;
  }
  displayName() {
    alert( `Hello ${this.nom}` );
  }
}

// sucharger la méthode displayName
class Administrator extends Utilisateur {
  constructor( nom, email, website ) {
    super( nom, email ); // appelle le constructeur parent
    this.website = website;
  }
  displayName() {
    super.displayName(); // appelle la méthode parent
    alert( `, your email is ${this.email}` );
  }
}

let tom = new Administrator("Tom Watson" , "tom@gmail.com", "https://tom.com" );

tom.displayName(); // Hello Tom Watson, your email is tom@gmail.com

Les objets globaux

Les objets globaux sont des objets natifs à JavaScript qui disposent d'un certain nombre de méthodes prédéfinies. Nous pouvons utiliser ces objets globaux pour créer d'autres objets.

Cependant lorsque cela est possible, on préfèrera utiliser les types primitifs qui sont plus performantes (mémoire utilisée) et avec lesquelles on va également pouvoir utiliser les propriétés et méthodes définies dans le constructeur.

// Objet String
let maChaine = new String('mon prénom est Gilles');
console.log( maChaine.length );

// primitive de type String
let maChaine = 'mon prénom est Gilles';
console.log( maChaine.length );

Voyons quelques objets globaux parmis les plus utilisés. Je n'irai pas dans le détails des propriétés et méthodes des ces objets, l'information étant accessible dans la documentation MDN.

L’objet String

L'objet String est un constructeur de chaînes de caractères.

Propriétés

length

Elle permet de connaître la taille d'une chaîne de caractères, l'espace étant aussi considéré comme un caractère.

let maChaine = 'mon prénom est Gilles'; // l'espace est un caractère
console.log('maChaine.length'); // 21

Attention, la propriété length ne renvoie pas toujours une valeur égale au nombre de caractères présents dans la chaîne car certain caractères spéciaux occupent deux unités.

Méthodes

Il existe de nombreuses méthodes pour l'objet String, voici quelques exemples utiles :

concat() : combine le texte de plusieurs chaînes avec la chaîne appelante et renvoie la nouvelle chaîne ainsi formée.

endswith() et startsWidth() : renvoie un booléen indiquant si la chaine de caractères se termine/commence par la chaine de caractères fournie en argument.

includes() : détermine si une chaîne de caractères est contenue dans une autre et renvoie true ou false selon le cas de figure.

indexOf() : renvoie l'indice de la première occurence de la valeur cherchée au sein de la chaîne courante (à partir de indexDébut). Elle renvoie -1 si la valeur cherchée n'est pas trouvée.

L’objet Number

L'objet Number est utilisé pour manipuler les nombres.

Propriétés

La plupart des propriétés de l’objet Number sont des propriétés dites statiques.

Méthodes

Beaucoup de méthodes de l'objet Number sont également statiques.

isInteger() permet de déterminer si une valeur est un entier valide.

toFixed() permet de formater un nombre en indiquant le nombre de décimales qu’on souhaite conserver.

L’objet Array

L'objet Array est utilisé pour créer des tableaux.

En JavaScript, les tableaux sont des objets. Ils permettent de stocker plusieurs valeurs et chaque valeur est identifiée par un indice. Les tableaux fonctionnent donc sur un système clé : valeur

En JavaScript, il n'existe que des tableaux numérotés, les indices sont des nombres incrémentés de "1" automatiquement, le premier indice commence à "0". Les tableaux associatifs (indice = chaine de caractères) n'éxiste pas en JavaScript. Si on souhaite utiliser un système de stockage de plsuieurs valeurs avec comme indice un littéral, il faut utiliser un objet.

// initialiser un tableau vide
const a = []
const a = Array()

// initialiser un tableau avec des valeurs
const a = [1, 2, 3]
const a = Array.of(1, 2, 3)

// indices avec litéraux > utiliser un objet
let pierre = {
    'prenom' : 'Pierre',
    'age' : 29,
    'sport' : 'trail',
    'cours' : ['HTML', ' CSS', 'js']
};

// tableaux multidimensionnels
const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

matrix[0][0] // 1
matrix[2][0] // 7

On peut stocker n’importe quel type de valeur dans un tableau, y compris un autre tableau (tableau multidimensionnel).

La synthaxe la plus performante pour créer un tableau est la suivante :

let villes [ 'Paris', 'Berlin', 'Rome', 'Montréal' ];
let personnage [ 'Pierre Kolman', 45,  ['74kg', '178cm'] ]; // un tableau peut contenir des types différents

On accède aux valeurs du tableau via les indices :

console.log( villes[0] ); // Paris
console.log( personnage[2][1] ); // 178cm

Pour parcourir tous les éléments d'un tableau, on utilise une boucle for… of spécialement créée dans ce but.

for ( let valeur of villes ) {
   console.log( valeur ); // Paris Berlin Rome Montréal
}

Pour un objet, on préférera une boucle for … in

for ( let propriete in pierre ) {
   console.log( pierre[propriete] ); // Pierre 29 trail HTML,CSS,js
}

Propriétés

length : Nombre d'éléments présents dans le tableau.

const a = [ 1, 2, 3 ]
a.length // 3

Il est possible d'assigner une taille au tableau. Si cette taille est inférieure au nombre d"éléments présents, le tableau est tronqué.

const a = [ 1, 2, 3 ]
a // [ 1, 2, 3 ]
a.length = 2
a // [ 1, 2 ]

Méthodes

push() : ajoute un ou plusieurs éléments à la fin du tableau.

pop() : retire un élément à la fin du tableau.

unshift() : ajoute un élément en début de tableau.

shift() : permet de retirer le premier élément d'un tableau et de renvoyer cet élément. Cette méthode modifie la longueur du tableau.

splice() : La méthode splice() modifie le contenu d'un tableau en retirant des éléments et/ou en ajoutant de nouveaux éléments à même le tableau.On peut ainsi vider ou remplacer une partie d'un tableau.

join() : La méthode join() crée et renvoie une nouvelle chaîne de caractères en concaténant tous les éléments d'un tableau (ou d'un objet semblable à un tableau). La concaténation utilise la virgule ou une autre chaîne, fournie en argument, comme séparateur.

slice() : La méthode slice() renvoie un objet tableau, contenant une copie superficielle (shallow copy) d'une portion du tableau d'origine, la portion est définie par un indice de début et un indice de fin (exclus). Le tableau original ne sera pas modifié.

concat() : permet de joindre plusieurs tableaux en un.

includes() : renvoie true si le tableau contient la valeur indiquée.

L’objet Math

L'objet Math est un objet natif dont les méthodes et propriétés permettent l'utilisation de constantes et fonctions mathématiques. L’objet Math va être utilisé lorsqu’on aura besoin d’effectuer des opérations mathématiques. Toutes les propriétés et méthodes de cet objet sont statiques.

Propriétés

Les propriétés de l’objet Math stockent des constantes mathématiques utiles.

Math.pi a pour valeur pi, soit environ 3,14159

Méthodes

L’objet Math possède des méthodes qui permettent d’arrondir des nombres, de générer des nombres aléatoires ou encore de calculer le cosinus, sinus, tangente, logarithme ou l’exponentielle d’un nombre.

floor() va arrondir la valeur passée en argument à l’entier immédiatement inférieur (ou égal) à cette valeur.

ceil(), au contraire, va arrondir la valeur passée en argument à l’entier immédiatement supérieur (ou égal) à cette valeur.

round() arrondi la valeur passée en argument à l’entier le plus proche.

random() permet de générer un nombre décimal compris entre 0 (inclus) et 1 (exclu) de manière pseudo-aléatoire.

L’objet Date

L'objet Date permet de créer des instances Date qui représentent un moment précis dans le temps. Les objets Date se basent sur une valeur de temps qui est le nombre de millisecondes depuis 1er janvier 1970 minuit UTC.

Le JavaScript stocke les dates en interne sous forme d’un Timestamp Unix exprimé en millisecondes (c’est-à-dire le Timestamp Unix multiplié par 1000).

Méthodes statiques

now() : Méthode statique de l'objet Date (pas besoin d'instanciation). Cette méthode retourne la valeur numérique correspondant au temps courant. Le nombre de millisecondes depuis le 1 janvier 1970, 00:00:00 UTC (Unix Epoch) sans compter les secondes intercalaires.

Méthodes d'instances

Pour créer et manipuler les dates, nous allons devoir instancier l'objet Date() pour pouvoir accéder à ses nombreuses méthodes. On peut instancier l'objet Date() sans passer d'arguments ou avec des arguments.

let date1 = new Date(); // heure courante dans le fuseau horaire locale
let date2 = new Date('March 23, 2019 20:00:00');
let date3 = new Date(1553466000000);
let date4 = new Date(2019, 0, 25, 12, 30);

Les méthodes peuvent être classées en getters ( obtenir / récupérer / lire qlq chose) et setters ( définir / modifier qlq chose ).

Getters

getDay() renvoie le jour de la semaine sous forme de chiffre (avec 0 pour dimanche, 1 pour lundi et 6 pour samedi) pour la date spécifiée selon l’heure locale.

getDate() renvoie le jour du mois en chiffres pour la date spécifiée selon l’heure locale.

getMonth() renvoie le numéro du mois de l’année (avec 0 pour janvier, 1 pour février, 11 pour décembre) pour la date spécifiée selon l’heure locale.

Setters

setDate() et setUTCDate() définissent le jour du mois en chiffres pour la date spécifiée selon l’heure locale ou l’heure UTC ;

setMonth() et setUTCMonth() définissent le numéro du mois de l’année (avec 0 pour janvier, 1 pour février, 11 pour décembre) pour la date spécifiée selon l’heure locale ou l’heure UTC ;

Comment convertir une date au format local ?

On va utiliser des méthodes prévues à cet effet :

toLocaleDateString() renvoie la partie « jour-mois-année » d’une date, formatée en fonction d’une locale et d’options.

toLocaleTimeString() renvoie la partie « heures-minutes-secondes » d’une date, formatée en fonction d’une locale et d’options.

toLocaleString() renvoie la date complète, formatée en fonction d’une locale et d’options.

let date1 = new Date();

let dateLocale = date1.toLocaleString( 'fr-FR', {
    weekday: 'long',
    year: 'numeric',
    month: 'long',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
    second: 'numeric'}
);

console.log( 'Date : ' + dateLocale ); 
// Date : mercredi 18 mars 2020 à 19:37:02

Manipulation du BOM - Browser Object Model

Une API (Application Programming Interface) est un ensemble de commandes mises à disposition des développeurs pour effectuer simplement de l'extérieur des opérations complexes sur une application tierce.

Les navigateurs web mettent à notre disposition des API :

- pour manipuler le DOM (Document Object Model) pour agir sur le code HTML et CSS d'une page web,

- pour manipuler des coordonnées de géolocalisation Geolocation,

- pour dessiner et manipuler des graphiques dans une page Canvas .

Ces APIs vont mettre à notre disposition des objets comportant des propriétés et des méthodes que nous pourront utiliser pour effectuer des opérations complexes.

Browser Object Model (BOM) et l’objet Window

Cette API permet de manipuler le navigateur web ( ouvrir/fermer des onglets, aller à une URL, mémoriser l'historique de navigation, etc ). Elle est composée d'objets hiérarchisés de la façon suivante :

BOM - hiérarchie des objets

Un objet Windows est associé à chacune des situations suivantes :

- Un onglet du navigateur

- Un pop-up

- Un frame ouvert dans un document

L'objet Window est « implicite », pas besoin de le mentionner pour utiliser les méthodes (ou fonctions globales) et propriétés (ou variables globales) lui appartenant.