Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Vue.js
  3. Notions essentielles de JavaScript
Extrait - Vue.js Développez des applications web modernes en JavaScript avec un framework progressif
Extraits du livre
Vue.js Développez des applications web modernes en JavaScript avec un framework progressif
2 avis
Revenir à la page d'achat du livre

Notions essentielles de JavaScript

Introduction

Vue.js est un framework JavaScript et se base donc sur ce langage. Il est important de connaître les bases de ce langage pour comprendre la syntaxe utilisée dans les exemples de code des prochains chapitres.

Le langage JavaScript, lancé par Netscape en 1995, permet aux pages web de réagir aux actions de l’utilisateur côté client.

Pour être ensuite implémenté par d’autres navigateurs, plusieurs spécifications ont été définies :

  • DOM (Document Object Model), normalisé par le W3C, est une API web permettant à des scripts d’analyser et de manipuler des langages de balisage comme HTML ou XML ;

  • ECMAScript, établi par Ecma International, est une spécification pour les langages de type script. Elle est utilisée par le langage JavaScript, mais aussi par ActionScript notamment.

Ces spécifications sont destinées à être communes à chaque navigateur. Il y a donc toujours un temps de retard entre la sortie d’une nouvelle version d’ECMAScript et son implémentation par les éditeurs dans l’interpréteur JavaScript de leur navigateur. C’est aussi, entre autres, pour cette raison qu’un grand nombre d’éléments syntaxiques était propres à chaque navigateur. Plus ces spécificités ont été normalisées, plus elles ont été dépréciées au fur et à mesure des différentes versions de navigateurs, pour privilégier celles de la spécification ECMAScript.

ECMAScript a beaucoup évolué et continue d’évoluer très rapidement ; nous en sommes aujourd’hui à la version 10 (ES10 - ES2019)....

Bases algorithmiques

1. Variables et types de valeurs

a. Déclaration d’une variable

Pour définir une variable, on peut utiliser les mots-clés var, let ou const. Une variable peut être initialisée en lui affectant une valeur ou le résultat d’une expression (opération, retour de fonction) directement lors de la déclaration.

Si elle n’est pas initialisée avec une valeur, elle est indéfinie et prendra par défaut la valeur undefined.

// déclarations des variables a, b et c : 
 
var a; // "undefined" 
let b; // "undefined" 
const c; // "undefined" 
 
// initialisation des variables e, f et g : 
 
var e = 1; 
let f = "bonjour"; 
const g = 1 + 0.45; 

En JavaScript, on utilise // pour commenter une ligne de code et /* */ pour commenter plusieurs lignes.

Contrairement aux langages fortement typés, JavaScript utilise un typage dynamique. Autrement dit, on peut affecter une variable avec une valeur d’un certain type, puis réaffecter celle-ci avec une valeur d’un autre type sans générer d’erreur.

let a = 2; 
a = "bonjour"; 

Il est également possible de déclarer plusieurs variables sur une seule ligne, en séparant chaque variable par une virgule :

let a = 1, b = 2, c = 3; 

b. Types de valeurs

En JavaScript, la valeur d’une variable peut être de six types primitifs différents. On différencie les types primitifs des types natifs d’objets qui possèdent des propriétés ou des méthodes.

Liste des types primitifs en JavaScript :

  • string : une chaîne de caractères

let a = "bonjour"; 
  • number : un nombre entier, décimal, ou la valeur NaN (Not a Number) quand une opération arithmétique ne peut pas renvoyer de nombre.

let a = 2; 
let b = 3.545; 
let c = 2 / 0; // NaN 
  • boolean :

let a = true; 
let b = false; 
  • object : peut être un objet déclaré de manière littérale, une instance d’objet ou un objet global. Il existe plusieurs objets globaux en JavaScript : Date, Math, String, Number, Boolean, JSON, window, document, etc. Pour les objets globaux associés à un type de donnée, on les appelle aussi...

Fonctions

1. Définition et utilisation des fonctions

Une fonction permet de créer un contexte d’exécution en dehors du contexte d’exécution global dès qu’elle est appelée. Autrement dit, une fonction permet de créer un bloc d’instructions qui pourra être exécuté plusieurs fois à plusieurs endroits du code avec son propre contexte d’exécution.

On évite ainsi la duplication d’un même bloc d’instructions utilisé à plusieurs endroits de l’application.

Une fonction se déclare avec l’instruction function, possède une signature et peut comporter plusieurs arguments en entrée.

Une fonction peut également renvoyer une valeur au contexte d’exécution parent avec l’instruction return.

Pour appeler une fonction, il suffit de réutiliser sa signature et de lui passer le même nombre de valeurs en paramètres qu’il y a d’arguments dans sa déclaration.

// déclaration d'une fonction sans argument 
function maFonction() { 
  console.log("fonction exécutée"); 
} 
 
// déclaration d'une fonction avec des arguments et une valeur de retour 
function additionner(nb1, nb2) { 
  return nb1 + nb2 
} 
 
// Appels 
maFonction(); // affiche "fonction exécutée" 
var somme = additionner(2, 3); 
console.log(somme); // 5 

Il est possible de déclarer une fonction en tant qu’expression. Elle peut alors être affectée à une variable, la fonction ne comporte ainsi pas de signature ; on appelle cela une fonction anonyme.

let affiche = function() { 
  console.log("fonction exécutée"); 
}; 
 
affiche(); 

2. Fermetures (closures)

Une fonction imbriquée dans une autre fonction est appelée fermeture (closure en anglais). C’est l’un des principes les plus intéressants du langage JavaScript.

Il est possible d’imbriquer en cascade plusieurs fonctions ; on parle également de chaînage de portée. Tout comme la différence entre la portée locale d’une fonction vis-à-vis de la portée...

Manipulation de tableaux

1. Déclarer, lire, modifier, supprimer des éléments

Un tableau permet de lister un ensemble de valeurs, de tout type, auxquelles on peut accéder via leur indice, c’est-à-dire leur position dans le tableau. L’indice d’un tableau commence toujours à 0. En JavaScript, un tableau correspond à l’objet natif Array et on peut utiliser ses méthodes pour le manipuler.

Pour créer un tableau, il est possible d’utiliser trois syntaxes différentes mais équivalentes :

let tab = ["pomme", "banane", "orange"]; 
let tab = Array("pomme", "banane", "orange"); 
let tab = new Array("pomme", "banane", "orange"); 

Pour lire l’élément d’un tableau, on utilise l’indice de sa position :

let elmt2 = tab[0]; // "pomme" 

Pour connaître la taille du tableau, c’est-à-dire le nombre d’éléments, on utilise la propriété length. Celle-ci équivaut au dernier indice du tableau + 1.

let taille = tab.length; // 3 

On peut remplir un tableau de plusieurs manières :

  • en précisant l’indice sur lequel on affecte une valeur ;

  • avec la méthode push, qui affecte une valeur à la fin du tableau sur un nouvel indice ;

  • avec la méthode unshift, qui ajoute un ou plusieurs éléments au début d’un tableau. ...

Manipulation d’objets

1. Définir un objet et son prototype

Un objet est un ensemble dynamique de propriétés. Une propriété est une paire composée d’un nom unique (aussi appelé clé) et d’une valeur qui lui est associée. On parle aussi de tableau associatif. On peut associer n’importe quelle valeur à une clé. Si l’on associe une fonction à une clé, on appelle cette propriété une méthode et les autres propriétés sont aussi appelées attributs.

let obj = { prop1: "valeur", prop2: 42 }; 
console.log(obj); 

Résultat :

images/02EI01.png

Lorsqu’on regarde le résultat du code suivant dans la console, on a un objet avec trois propriétés : prop1, prop2 et __proto__.

__proto__ est une propriété spéciale. Cette propriété est en fait un lien vers un objet parent que l’on appelle prototype.

Tous les objets possèdent ce lien quand ils sont créés. Ici, l’objet parent est de type Object et notre objet hérite alors de toutes ses méthodes.

Lorsqu’on cherche à accéder à une propriété, JavaScript cherche d’abord cette propriété dans l’objet, puis, s’il ne la trouve pas, remonte le lien et la cherche ensuite dans son prototype. Si, de nouveau, il ne la trouve pas dans le prototype, il cherche ensuite dans le prototype du prototype, et ainsi de suite.

Ces liens de prototype en prototype forment ce que l’on appelle la chaîne de prototypage. 

images/02EI02.png

Prenons l’exemple de la méthode hasOwnProperty du prototype de notre objet. Celle-ci renvoie true si la valeur passée en paramètre est un nom de propriété de l’objet :

obj.hasOwnProperty('prop1'); // true 
obj.__proto__.hasOwnProperty('prop1') // false 
obj.__proto__.hasOwnProperty('hasOwnProperty') // true 

Tous les objets héritent donc en cascade des attributs et méthodes de l’ensemble des prototypes de la chaîne de prototypage. Il ne s’agit pas à proprement parler du même mécanisme d’héritage que l’on retrouve dans beaucoup de langages orientés objet. Il s’agit de liens entre objets quand...

Utilisation du mot-clé this

1. En dehors d’une fonction

Le mot-clé this se comporte légèrement différemment en JavaScript que dans les autres langages, où il désigne l’objet dans lequel il est utilisé.

En dehors de toute fonction, dans le contexte d’exécution global, this désigne l’objet window dans un navigateur et l’objet global si le code est exécuté côté serveur (exemple avec Node).

this === window; // true sur un navigateur 
this === global; // true sur un serveur 

2. Dans une fonction appelée de manière classique

Dans une fonction, la valeur de this dépend de la façon dont elle est appelée et sa valeur peut être différente à chaque appel si elle est appelée avec les méthodes call(), apply().

Avec un appel simple de fonction, this doit obligatoirement désigner un objet si la fonction n’est pas en mode strict. Il s’agira donc de l’objet window par défaut dans un navigateur.

Avec le mode strict, si this n’est pas défini, il aura la valeur undefined.

function test() { 
  return this; 
} 
 
// appel simple sans mode strict 
test() === window; // true  
 
function test2() { 
  "use strict"; 
  return this; 
} 
 
// appel simple avec mode strict ...

Gestion des exceptions

1. L’utilité

Lorsqu’on développe une application, on peut être amené à faire des bogues du fait d’erreurs de syntaxe ou d’algorithmie (boucle infinie, appels de fonctions récursives infinies ou saturation de la mémoire, etc.). Lors de l’exécution, JavaScript remontera alors ces erreurs dans la console. Lorsqu’une erreur s’affiche, on dit aussi qu’une exception a été levée. Il n’est pas judicieux de gérer la levée de ces exceptions dans le code. Il est préférable de le réécrire pour le corriger.

Mais il peut être utile de prévoir la levée de plusieurs exceptions liées à l’utilisation du programme par l’utilisateur (clics intempestifs, trop de fichiers ouverts, vouloir traiter un volume de données trop important, etc.) ou liées à l’utilisation de services externes (requêtes API qui ne renverraient pas les réponses attendues, par exemple). On pourra ainsi afficher un message d’avertissement ou d’erreur à l’utilisateur.

2. La structure try…catch…finally

Pour lever une exception, on utilise l’instruction throw. Lorsque JavaScript rencontre cette instruction, il arrête l’exécution du contexte courant et remonte la pile d’appels, de fonction en fonction avec leurs différentes portées, jusqu’à la portée d’un bloc try. Il lit ensuite le bloc d’instructions de l’instruction catch liée. L’instruction catch est appelée comme une fonction et prend en paramètre la variable levée par l’instruction throw.

function maFonction() { 
  let message = "une erreur s'est produite"; 
  throw message; // levée d'exception 
  var x = 1; // code...

Utilisation des promesses

1. Objet natif Promise

Une promesse désigne le type d’objet natif Promise. Celui-ci permet d’encapsuler une fonction qui sera exécutée de manière asynchrone. Tant que l’exécution du traitement asynchrone n’a pas commencé, l’état de la promesse est en attente.

Lors de l’exécution de ce traitement, on dit qu’on "consomme" la promesse. Le résultat peut être la complétion ou l’échec de ce traitement. On dit alors que la promesse est tenue ou rompue.

On crée une promesse avec l’instruction new. Le constructeur Promise() prend en paramètre d’entrée une fonction que l’on appelle aussi l’exécuteur.

L’exécuteur prend lui-même en paramètres deux autres fonctions : resolve et reject

new Promise(function(resolve, reject) {/* ... */}); 

L’appel de resolve ou reject permet de tenir ou rompre la promesse.

La fonction resolve(valeur) termine le traitement asynchrone et appelle le premier gestionnaire de la méthode then() (qu’on appellera "siTenue") avec la valeur, dite de résolution, qu’on lui passe en paramètre.

La fonction reject(raison) termine également le traitement asynchrone et appelle le deuxième gestionnaire (qu’on appellera "siRejetée") de la méthode then() avec la raison qu’on lui donne en paramètre.

Chaque gestionnaire n’est autre qu’une fonction qui sera ensuite appelée dans la méthode then().

2. Méthode then()

Pour consommer une promesse, on utilise la méthode then() de l’objet Promise. Cette méthode prend deux fonctions de rappel en paramètres d’entrée. La première fonction représente le gestionnaire appelé par la méthode resolve() de la promesse lorsqu’elle est tenue.

La deuxième fonction de rappel représente le gestionnaire appelé par la méthode reject() de la promesse lorsqu’elle est rejetée.

const promesse = new Promise((resolve, reject) => { 
  resolve("traitement terminé"); 
  // reject("erreur"); 
}); 
 
promesse.then(siTenue); ...

Utilisation des modules JavaScript

1. L’historique des modules JavaScript

a. Introduction

Au fil des années, plus les appareils, ordinateurs, tablettes et smartphones, sont devenus puissants, plus les applications web ont embarqué de la logique métier côté client plutôt que côté serveur, dans le but de raccourcir les temps de réponse aux utilisateurs. Elles ont donc utilisé de plus en plus de code JavaScript, notamment au travers d’une multitude de librairies.

Côté client, cela a ensuite rapidement donné lieu au concept de SPA (Single Page Application). Ce sont des applications web monopages communiquant le plus souvent via des appels API avec les serveurs pour fluidifier l’expérience utilisateur. Aujourd’hui, les frameworks JavaScript comme Vue.js, React.js ou Angular permettent de développer facilement ce genre d’application.

JavaScript s’est aussi invité côté serveur et est de plus en plus utilisé avec le framework Node.js, par exemple.

Il a donc été nécessaire que le langage se dote de mécanismes pour découper et organiser plus facilement le code JavaScript. Le concept de module est venu répondre à cette problématique.

Un module permet d’encapsuler plusieurs fonctionnalités dans une brique logicielle aussi appelée "package". L’idée est ensuite d’employer une interface unifiée pour importer un module dans d’autres modules afin d’utiliser ses fonctionnalités ; ceci afin d’éviter que les variables et fonctions d’un module ne soient toutes chargées dans le contexte d’exécution global. Lorsqu’un module utilise des références d’autres modules, on dit alors qu’il possède des dépendances. On utilise généralement un fichier par module.

Les modules JavaScript ont beaucoup évolué ces dix dernières années et nombre de nouveaux termes ont fleuri dans l’écosystème JavaScript : CommonJS, AMD (Asynchronus Module Definition), RequireJS, Bower, Browserify, Webpack, Babel, Npm, NodeJS, sans qu’il soit facile de savoir exactement ce que c’est, ni lorsqu’on...