Cours de JavaScript - Bonnes pratiques de codage en javascript

version 1.21, dernière mise à jour le 19 décembre 2012.

  

Table des matières (TdM)

  1. I. Introduction
  1. II. Généralités
    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
      2. Ne pas écraser d'informations déjà présentes
      3. 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
  1. III. Lever les ambiguïtés des variables
    1. Introduction
    2. Création et utilisation d'un objet
      1. Création simple d'un objet
      2. Création d'un littéral objet
      3. Exercice : Définitions simples d'objets
    3. Interdire la manipulation de certaines propriétés : l'encapsulation
      1. Exercice : Création d'objet avec membre privé
  1. IV. Gestion des événements
    1. Lancement d'un script au chargement de la page
      1. Exercice : Suppression de l'attribut onload
    2. 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 :

>Retour à la TdM

Heureusement, de « bonnes pratiques » de codage permettent de ne pas tomber dans ces pièges. On pourra consulter avec profit le blog de Christian Heilmann, intitulé Wait-till-I-come.

II. Généralités

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 de la page. 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, de 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

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 a pour conséquence de préférer systématiquement l'utilisation de la propriété className aux 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"; 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.

>Retour à la TdM

b. Ne pas écraser d'informations déjà présentes

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é. Afin de l'éviter, il faut tester au préalable si className existe pour l'élément en question, puis ajouter la nouvelle classe à son contenu si c'est le cas.

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.

>Retour à la TdM

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 pour 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

III. Lever les ambiguïtés des variables

1. Introduction

Il arrive que des variables soient redéfinies entre plusieurs scripts épars dans des fichiers distincts. Une redéfinition malencontreuse d'une variable peut perturber le fonctionnement d'un script, et il faut donc au maximum limiter le risque d'interférences entre deux variables. La toute première précaution à prendre est donc de limiter au maximum la portée d'une variable, en recourant à la déclaration var.

>Retour à la TdM

On pourrait penser à utiliser des noms de variables très explicites, voire à les préfixer ou les suffixer, comme par exemple monCodeAMoiRienQuAMoi_maVariable, mais il faut pour cela trouver un préfixe unique (celui de l'exemple précédent a certes peu de chances d'être repris !), et surtout, par la suite, se garder des fautes de frappe. Qui plus est, cela a comme inconvénient que si par extraordinaire, le préfixe est utilisé dans un autre fichier, l'ensemble des variables et fonctions doit être renommé. Ce n'est donc pas une solution très efficace.

>Retour à la TdM

2. Création et utilisation d'un objet

a. Création simple d'un objet

JavaScript ne permet pas comme d'autres langages de définir des classes, et d'instancier ensuite des objets. Mais il est possible de créer directement des objets, grâce au mot-clef Object.

var objet1 = new Object ;

objet1.chaine="Bonjour!" ;
objet1.affiche=function(){
  alert(this.chaine) ;
}

objet1.affiche() ;

La déclaration précédent définit l'objet objet1, lui attache une propriété (chaine) et une méthode que l'on appelle ensuite. Ainsi, la méthode est associée à cet objet uniquement, et il n'y a pas de risque que sa définition écrase une autre définition qui serait donnée pour un autre objet.

>Retour à la TdM

b. Création d'un littéral objet

Il est possible d'aller un peu plus loin dans la création d'un objet en utilisant un « littéral objet », mais cette méthode ne fonctionne pas pour les navigateurs anciens (Netscape jusqu'à la version 3 et Internet Explorer jusqu'à la version 4) La déclaration précédente s'écrit alors...

var objet1 =
{
  chaine:"Bonjour!",
  affiche:function()
    {
      alert(this.chaine) ;
    }
}
objet1.affiche() ;

Cela permet de ne pas avoir à répéter le nom de l'objet défini, réduit donc les risques d'erreur et facilite la maintenance et la reprise ultérieure du code. Attention, dans l'exemple précédent, les lignes dans le littéral sont séparées par des virgules, et les définitions utilisent des : et non des points-virgule.

Exercice 1. Définitions simples d'objets

Énoncé
Correction (définition d'un objet)
Correction (définition d'un littéral objet)

>Retour à la TdM

3. Interdire la manipulation de certaines propriétés : l'encapsulation

Il est possible d'aller encore un peu plus loin. En effet, il n'est parfois pas souhaitable que certaines propriétés d'un objet soient accessibles de l'« extérieur » du script. En programmation orientée objet, on fait appel, dans une classe, à des membres dits privés et d'autres publics. Il est possible de faire de même en javascript, en utilisant le fait qu'une fonction est un objet, et que la portée des variables qui y sont déclarées y est limitée. Ainsi,

var livre = new function()
{
  //Membres privés
  var chaine = "Test" ;
  function allerA(Page)
    {
      (...)
    }
  function sauterDixPages()
    {
      (...)
    }

  //Membres publics: attention, il ne doit pas y avoir de retour à la ligne entre return et l'accolade
  return   {
    ouvrir : function()
      {
        allerA(1) ;
      } ,
    allerA : allerA
  } ;
} ;

Dans le code précédent, seules les méthodes ouvrir et allerA sont disponibles. Cela permet en outre de rassembler en tête de la déclaration tout ce qui relève d'une configuration. Par exemple...

var livre = newfunction()
{
  //Configuration à éditer
  var config={
    pageParDefaut : "1" ,
    titre : "Titre par défaut"} ;

  //Membres privés
  var chaine = "Test" ;
  function allerA(Page)
    {
      (...)
    }
  function sauterDixPages()
    {
      (...)
    }

  //Membres publics
  return   {
    ouvrir : function()
      {
        allerA(config.pageParDefaut) ;
      } ,
    allerA : allerA
  } ;
} ;

Exercice 1. Création d'objet avec membre privé

Énoncé
Correction

>Retour à la TdM

IV. Gestion des événements

1. 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 Internet Explorer :

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

Exercice 1. Suppression de l'attribut onload

Énoncé
Correction

>Retour à la TdM

2. 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