Cours de JavaScript - Bonnes pratiques de codage en javascript

version 2.3.0, dernière mise à jour le 21 novembre 2018.

   

Table des matières (TdM)

  1. I. Introduction
  1. II. Précautions élémentaires
    1. Ajout de contenu
      1. Exercice : Masquage d'éléments au chargement d'une page
    2. La mise en forme doit être effectuée à l'aide de CSS
      1. Préférer className/classList
      2. Exercice : Ajout d'une classe
    3. Conditionner l'exécution d'un code
      1. Tester la disponibilité d'une méthode ou d'une propriété
      2. Tester la présence d'un élément
      3. Exercice : Tester la disponibilité d'une méthode
      4. Exercice : Tester la présence d'un élément
    4. Une gestion stricte des erreurs et un gain de performances avec le mode strict
      1. Introduction
      2. Invoquer le mode strict
      3. Quelques différences du mode strict
  1. III. Chargement et exécution des scripts
    1. Où placer l'élément script
      1. Avant ou après ?
      2. Les attributs defer et async
    2. Lancement d'un script au chargement de la page
      1. Exercice : Suppression de l'attribut onload
      2. Événement DOMContentLoaded
  1. IV. Divers
    1. Contrôle des événements souris et clavier
      1. Exercice : Spécifier des événements clavier et souris

Retour au menu

Contenu du cours

I. Introduction

Il est courant de rencontrer sur Internet des codes JavaScript écrits par d'autres programmeurs, et que l'on souhaite incorporer à ses pages. Il arrive aussi que l'on souhaite réutiliser du contenu, des fonctions que l'on a soi-même écrites précédemment.

Cependant, ce désir de vouloir reprendre du code de sources externes se heurte souvent à des difficultés :

Heureusement, de « bonnes pratiques » de codage permettent de ne pas tomber dans ces pièges.

II. Précautions élémentaires

1. Ajout de contenu

Nous avons vu dans un chapitre précédent comment ajouter du contenu à un document. Cependant, cette possibilité présente de gros inconvénients en termes d'accessibilité : les utilisateurs ne disposant pas de JavaScript sont dans l'incapacité de consulter ce contenu si des précautions ne sont pas prises.

À cet égard, il est primordial que tout contenu informatif présent dans un document doit être présent dans le code HTML. Par exemple, il ne faut pas utiliser JavaScript pour ajouter, par exemple, un menu de navigation.

Une alternative consiste à faire en sorte que le contenu soit déjà présent dans la page, puis, au chargement du document, le cacher par JavaScript pour ensuite le faire réapparaître en fonction des besoins.

Exercice 1. Masquage d'éléments au chargement d'une page

Énoncé
Correction

>Retour à la TdM

2. La mise en forme doit être effectuée à l'aide de CSS

a. Préférer className/classList

CSS est un langage qui est dédié à la mise en forme. Par conséquent, il est toujours plus rapide de changer l'apparence d'un élément en faisant appel à CSS qu'à JavaScript. Cela implique de préférer systématiquement l'utilisation de la propriété className ou classListaux propriétés de l'objet style. Par exemple, si l'on doit changer en rouge la couleur d'un élément elt, on définira de préférence une classe "exemple" qui spécifiera une couleur de police rouge et on fera elt.className="exemple"; ou, mieux, elt.classList.add("exemple"); au lieu d'indiquer elt.style.color="red". Cela offre en outre l'avantage d'externaliser en-dehors du script la définition de cette mise en forme.

Attention, certains éléments sont déjà pourvus d'une classe dans le code HTML. Manipuler la propriété className peut faire perdre une mise en forme. Rappelons en effet qu'il est tout à fait possible pour un élément d'avoir plusieurs classes : <span id="span1" class="classe1 classe2 classe3">(…)</span>. Si on utilise directement span1.className="classe3", par exemple, l'élément va perdre toutes ses autres classes, ce qui n'est pas forcément le but recherché ; il peut aussi arriver que l'élément possède déjà la classe que l'on souhaite ajouter.

Exercice 1. Ajout d'une classe

Énoncé
Correction

>Retour à la TdM

3. Conditionner l'exécution d'un code

a. Tester la disponibilité d'une méthode ou d'une propriété

Avant de faire appel à une propriété ou une méthode, il vaut mieux au prélable s'assurer qu'aucune erreur ne sera produite si elle n'est pas disponible. Il était d'usage de faire une détection du navigateur utilisé, mais cette pratique a disparu pour laisser place à des méthodes plus efficaces.

Il suffit en effet de tester si ce dont on a besoin ne produit pas de code erreur, et de conditionner la poursuite de l'exécution du code au fait qu'il n'y a pas d'erreur.

Supposons par exemple que l'on souhaite utiliser la méthode getElementById. On écrira…

if (!document.getElementById) return ;

//Code à exécuter quand getElementById est supporté.

Ainsi, le navigateur ignorera « naturellement » le code qu'il ne peut pas comprendre.

b. Tester la présence d'un élément

Avant d'agir sur un élément, encore faut-il être sûr qu'il existe… Cela peut paraître superflu quand on n'intervient que sur une seule page, mais lorsque le fichier JavaScript est amené à être mis en commun entre plusieurs documents, il est possible que le cas apparaisse où un élément n'existe pas sur une page… ce qui peut amener des erreurs.

Selon le cas, on peut alors soit placer les instructions réservées à un élément à l'intérieur d'un test, soit stopper l'exécution du script :

if (document.getElementById("id1"){
  //Code à exécuter quand l'élément d'identifiant id1 existe.
}

if (!document.getElementById("id1") return ;

{
  //Code à exécuter quand l'élément d'identifiant id1 existe.
}

Exercice 1. Tester la disponibilité d'une méthode

Énoncé
Correction

Exercice 2. Tester la présence d'un élément

Énoncé
Correction

>Retour à la TdM

4. Une gestion stricte des erreurs et un gain de performances avec le mode strict

a. Introduction

Le mode strict est un mode de fonctionnement de JavaScript où l'interpréteur est moins tolérant à des imprécisions de syntaxe. Nativement en effet, de même qu'en HTML les navigateurs mettent en œuvre des stratégies diverses pour résoudre les cas où le code n'est pas strictement conforme à la DTD, les interpréteurs JavaScript passent sous silence un certain nombre d'avertissements. Un inconvénient majeur est que cette mansuétude alourdit le temps d'analyse du script ; passer en mode strict entraîne donc des gains de performance. De plus, ce mode interdit l'usage de mots-clefs qui sont anticipés pour les futurs développements d'ECMAScript.

b. Invoquer le mode strict

On invoque le mode strict en ajoutant…

"use strict" ;

Cette ligne doit être ajoutée en tout début de script si l'on souhaite que ce mode s'applique globalement, ou bien avant quelque instruction que ce soit au début d'une fonction. Il y a cependant un inconvénient ; il est certes possible de passer en mode strict progressivement, fonction après fonction mais si on concatène le code total et si on commence par du code strict, alors l'ensemble du code concaténé sera considéré comme strict, ce qui peut engender nombre d'erreurs. De même, concaténer un code strict avec du non strict en commençant par du non strict fait que l'ensemble du code concaténé sera en non strict, et on perd les avantages du mode strict.

c. Quelques différences du mode strict

Un certain nombre d'erreurs silencieuses en non strict deviennent explicites en mode strict, et lèvent des exceptions. Par exemple, si on écrit dans une fonction…

'use strict' ;
maVariable = 42 ;

… alors cela générera une erreur. En effet, le mode strict rend impossible la création par inadvertance d'une variable globale. Nous aurons l'occasion d'y revenir, mais créer une variable globale ajoute en fait une propriété à l'objet global de la page, à savoir window. Si l'on veut déclarer une variable globale, il faut le faire explicitement, en écrivant par exemple ici window.maVariable = 42;

Le mode strict détecte aussi une erreur de syntaxe quand dans la déclaration (pas l'appel, où cela est autorisé) d'une fonction, des paramètres sont passés en double, alors que cette erreur, en mode non strict, le dernier argument dupliqué cache les précédents portant le même nom :

maFonction = function(x, y, y){
  "use strict" ;
  return x+y+z ;
}

Le code précédent déclenche une erreur dès l'analyse par l'interpréteur, mais uniquement lors de son exécution si on revient en mode non strict.

En mode strict également, il n'est pas possible de modifier par inadvertance la valeur d'une variable externe ou globale lors de l'appel à une fonction eval() :

var x1 = "hop" ;
var x2 = "hop" ;
var ynonstrict = eval(var x1 = 'hophop'; x1) ;
var ystrict = eval('use strict'; var x2 = 'hophop'; x2) ;

console.log("x1 = "+x1) ;
console.log("x2 = "+x2) ;
console.log(ynonstrict) ;
console.log(ystrict) ;

À l'issue de ce code, ynonstrict et ystrict valent "hophop", x1 vaut aussi "hophop" car sa valeur a été modifiée lors de l'évaluation de ynonstrict, mais x2 vaut encore "hop" car l'usage du mode strict lors de l'évaluation de ystrict en a empêché la modification.

Enfin, en mode strict, il est interdit de déclarer une fonction ailleurs qu'au niveau le plus haut d'un script ou d'une autre fonction. Par exemple, il est interdit de déclarer une fonction à l'intérieur d'une boucle for ou d'un test if.

>Retour à la TdM

III. Chargement et exécution des scripts

1. Où placer l'élément script

a. Avant ou après ?

Il existe deux grandes « écoles » de placement de l'élément script :

b. Les attributs defer et async

Les attributs defer et async permettent de gérer l'ordre de chargement des scripts.

Ces attributs peuvent maintenant être avantageusement remplacés par les « promesses » JavaScript, sur lesquelles nous reviendrons.

>Retour à la TdM

2. Lancement d'un script au chargement de la page

Nous avons jusqu'à présent chargé nos fonctions Init à l'aide de l'attribut onload de l'élément body. Cependant, il y a fort à parier que si l'on fait appel à d'autres scripts, le chargement de la page soit perturbé, et qu'il y ait des conflits. Il faut en effet au préalable s'assurer qu'aucun script ne se lance au même moment. S'il y en déjà un, il faut ajouter le nouveau script.

Heureusement, la méthode addEventListener permet d'ajouter un gestionnaire à ceux qui existent éventuellement déjà. On peut alors l'utiliser, mais dans le cadre d'une méthode plus large, que nous appellerons addLoadListener, qui est compatible avec les versions 8 et antérieures d'Internet Explorer :

function addLoadListener(gestionnaire){
  if (window.addEventListener)
    {
      window.addEventListener('load' gestionnaire false) ;
    }
  else if (document.addEventListener)
    {
      document.addEventListener('load' gestionnaire false) ;
    }
  else if (window.attachEvent)
    {
      window.attachEvent('onload' gestionnaire) ;
    }
}

Exercice 1. Suppression de l'attribut onload

Énoncé
Correction
b. Événement DOMContentLoaded

Un des inconvénients liés à load est que cet événement n'est lancé qu'une fois tout le document chargé : DOM, images, feuilles de style, etc. L'événement DOMContentLoaded est quant à lui lancé quand le DOM a été chargé, autrement dit la structure de la page, donc en particulier avant tout téléchargement d'image. On l'utilise en ajoutant le gestionnaire d'événement à l'objet document : document.addEventListener("DOMContentLoaded", gestionnaire, false).

>Retour à la TdM

IV. Divers

1. Contrôle des événements souris et clavier

Afin de préserver au maximum les possibilités d'interagir avec le document avec le clavier, il est recommandé de n'affecter des événements de clic que sur des éléments susceptibles de recevoir le « focus » clavier, à savoir a, area et les éléments de formulaire.

Exercice 1. Spécifier des événements clavier et souris

Énoncé
Correction (Événements souris)
Correction (Événements clavier et souris)

>Retour à la TdM

Historique de ce document

Conditions d'utilisation et licence

Creative Commons License
Cette création est mise à disposition par Gilles Chagnon sous un contrat Creative Commons.

Retour au menu