Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici

Bien démarrer vos projets

Choisir votre environnement de développement

1. Introduction

Longtemps en manque d’EDI (Environnement de Développement Intégré) ou relayé à une édition par simple éditeur de texte, les développeurs web se sont focalisés sur les assistants de pages HTML/CSS en oubliant JavaScript. L’évolution du langage a voulu que l’on passe d’un usage plutôt marginal à un usage massif notamment avec l’arrivée du mobile et de HTML 5. Nombre d’éditeurs se sont adaptés et offrent maintenant des environnements complets. Il est bien sûr toujours possible d’utiliser un éditeur de texte généraliste (comme Notepad++, vi, Emacs...) et travailler avec, mais c’est souvent se priver d’assistants précieux spécifiques à JavaScript et d’un réel gain de temps pour votre travail.

Voici quelques points indispensables qu’un EDI JavaScript doit gérer :

  • Gestion de l’encodage des caractères (UTF-8, ISO-8859-1...).

  • Coloration syntaxique.

  • Vérification syntaxique temps réel.

  • Assistants à la saisie.

  • Refactoring (simplification de la maintenance du code).

  • Formatage du code.

  • Gestion en projets.

Lorsque vous créez un fichier JavaScript, il est préférable d’utiliser un encodage portable de type UTF-8. Ce type d’encodage unicode peut contenir une séquence de caractères en début de fichier dite BOM (Byte Ordre Mark) qui est là pour indiquer l’ordre des octets mais sert également au repérage de l’encodage unicode UTF-8, UTF-16 ou UTF-32. Il est plutôt préférable de ne pas employer cette marque car tous les éditeurs/outils ne la supportent pas.

La coloration syntaxique et la vérification syntaxique sont liées. Le gain de temps peut être important de par l’usage de parenthèses et d’accolades important en JavaScript. Les imbrications de fonctions et d’objets peuvent rendre la syntaxe difficilement lisible. Le fait d’avoir une alerte au moment de la saisie est un précieux gain de temps qui vous évitera d’attendre l’étape d’exécution et l’interprétation du message d’erreur dans un navigateur.

Un assistant...

Organiser votre code

1. Séparer le code de la présentation

Dans un usage Web, il est plus lisible d’éviter tout mélange de code entre la partie présentation et la partie traitement, l’objectif étant de maintenir l’un ou l’autre plus simplement en réduisant les effets de bord.

Voici un exemple peu correct qui affiche la date au moment de l’affichage de la page (pour information l’attribut type de la balise script n’est plus indispensable en HTML5).

<html> 
    <head>
        <title>Test</title>
    </head>
    <body> 
        <h1>Bonjour</h1> 
        <script type="text/javascript"> 
            document.writeln( "Il est " + new Date() ); 
        </script> 
    </body> 
</html> 

Le code JavaScript est dans la balise body, ce qui n’est généralement pas une bonne idée. L’usage de document.writeln est à bannir autant que possible car n’intervenant qu’au moment de l’interprétation par le navigateur de la balise script, cela oblige donc à mettre le code à un endroit exact provoquant un mélange inévitable entre le code de la présentation et le code de traitement. 

Ce code est donc très peu maintenable. Pour l’améliorer, il est tout d’abord possible de remonter le script dans la balise head de la page. Bien entendu, en agissant ainsi, nous ne pouvons plus utiliser writeln (cette méthode écrit dans le flux de la page en cours de chargement et la balise head n’est pas une balise ayant un contenu visible pour l’utilisateur final) et il faut mettre à jour le contenu de la page au moment de son chargement complet afin de déterminer la zone qui va contenir le résultat du code. La balise body devient alors une sorte de gabarit de page. L’utilisation de l’API DOM permet d’ajouter le résultat (voir le chapitre dédié au développement Web)....

Portée des variables et fonctions

1. Portée des variables

Lorsque vous déclarez une variable, cette dernière n’est « accessible » qu’à certains endroits. Lorsque votre variable est déclarée en dehors de toute fonction, sa portée est dite globale, elle est donc disponible partout dans votre code.

a = 10; 
 
function test() { 
  alert( a ); 
} 
 
test(); 

Dans l’exemple, nous avons initialisé une variable a à 10. Elle est implicitement déclarée au moment de son usage. Étant en dehors de toute fonction, sa portée est donc globale.

Supposons maintenant que nous écrivions :

function test() { 
  a = 10; 
} 
test(); 
alert( a ); 

Nous avons maintenant initialisé la variable a dans la fonction test. Comme nous avons une déclaration implicite, nous nous serions attendus à ce que a ne soit plus globale. Or c’est exactement l’inverse, la variable a déclarée dans la fonction test est bien globale par défaut et nous pouvons afficher sa valeur en dehors de la fonction test.

Cela n’est pas acceptable car nous pourrions corrompre l’exécution de nos fonctions en cas d’usage d’un même nom de variable.

Pour éviter ce type de désagrément, nous disposons...

Optimisation de la portée

1. Limiter le contexte global

Les déclarations dans le contexte global sont une mauvaise chose en termes de qualité mais également en termes de performance.

Concernant la qualité, plus vous avez de déclarations dans l’espace de noms global et plus vous avez des chances d’avoir un conflit en modifiant une variable par erreur. Ce type de conflit peut venir de diverses manières : soit parce que votre code est devenu de plus en plus gros et que vous ne pouvez plus contrôler toutes vos déclarations, soit parce que vous ajoutez de nouvelles librairies. Si votre code est amené à évoluer, il est important de prendre en compte ce problème au moment de la conception.

Concernant les performances, la lecture d’une variable locale est environ deux fois plus rapide que la lecture d’une variable globale, la raison étant que l’interpréteur JavaScript commence toujours par tester le contexte local avant de regarder le contexte global. Lire une variable globale revient donc à faire un test supplémentaire pour l’interpréteur.

Dans l’exemple suivant, nous avons créé deux boucles effectuant un calcul simple, l’une utilisant le contexte global et l’autre le contexte local. Puis nous avons mesuré la différence d’exécution en millisecondes.

var i = 0; 
var j = 0; 
// Version globale 
var test1 = function() { 
    for ( i = 0; i < 1000000; i++ ) { 
        j += j; 
    } 
} 
 
// Version locale 
var test2...

Simplifier vos expressions

1. L’opérateur ||

Vous connaissez l’opérateur booléen ||. Cet opérateur effectue un « ou logique », mais il a également la particularité de retourner la première valeur évaluée comme vrai (true). En JavaScript, une valeur est implicitement vrai si elle est différente de false, undefined, 0, null et "" et inversement pour une valeur à faux.

Exemple :

var a = null; 
var b = a || 10; 
alert( b ); 

Dans notre exemple, nous avons initialisé la variable a à null (donc implicitement à faux), la variable b reçoit la dernière valeur qui est vraie, c’est-à-dire la valeur 10.

L’opérateur || peut donc être utilisé pour garantir une valeur de manière pratique.

function test( a ) { 
  a = a || 10; 
  alert( a ); 
} 
test(); 
test( 11 ); 

Dans cet exemple, nous avons un paramètre a qui peut ou ne pas être renseigné ; s’il ne l’est pas, il obtiendra automatiquement la valeur 10 par défaut. Nous aurons donc à l’affichage 10 lors d’un appel sans paramètre et 11 lors d’un appel avec le paramètre.

Il est également possible d’avoir un paramètre contenant un ensemble de propriétés partiellement présentes.

function action( config ) { 
    var defConfig = { 
        couleur : "blue", 
        font : "arial" 
    }; 
    config = config || defConfig; 
    var couleur = config.couleur || defConfig.couleur; 
    var font = config.font || defConfig.font; 
    alert( couleur + " et " + font ); 
} 
 
action(); 
action( { couleur : "red" } ); 
action( { couleur : "red", font : "times" } ); 

Dans la fonction action, nous avons un paramètre optionnel config, ce dernier contient en partie ou en totalité les propriétés couleur et font. Grâce à l’opérateur ||, nous avons toujours...

Passage au mode strict

1. Usage

Le mode strict est une nouveauté de la norme ECMAScript 5 (supportée à partir de Firefox 4+, Internet Explorer 9+, Safari 5.1+, Opera 11.6+, Chrome 13.0+), il s’agit d’un moyen pour améliorer la qualité de votre code à moindre coût. Il est également là pour vous faciliter la transition vers les prochaines versions de JavaScript. 

Ce mode s’active en tête de votre code ou de vos fonctions par la chaîne suivante :

"use strict"; 

Elle indique à votre navigateur que vous n’autorisez plus certains codes et qu’une erreur de syntaxe doit être levée lorsqu’ils sont détectés. À noter que placer cette chaîne en tête de votre code ou de vos fonctions est parfaitement compatible avec les navigateurs ne gérant pas ce mode (une chaîne est une expression ne provoquant rien).

Exemple d’une fonction en mode strict :

<html> 
    <head> 
        <script type="text/javascript"> 
            function test() { 
                "use strict"; 
                aa = 10; 
            } 
            test(); 
        </script> 
    </head> 
    <body> ...

JSHint

1. Usage de base

JSHint (http://www.jshint.com) est une librairie JavaScript s’appuyant sur JSLint (un projet similaire). Son objectif est d’analyser votre code et de vous avertir si des améliorations peuvent être effectuées. Cela ne concerne pas forcément des erreurs en soi, il s’agit plus de contrôle de qualité de code comme par exemple l’indentation, le passage systématique en mode strict

À la base, JSHint fonctionne grâce à une fonction globale JSHINT prenant trois arguments :

  • Votre code source JavaScript.

  • Un ensemble d’options indiquant à JSHint ce qu’il doit contrôler dans le code comme la vérification de blocs vides, l’indentation, la convention de nommage…

  • Un ensemble de variables globales non obligatoires avec un « flag » (booléen) pour indiquer si elles peuvent être modifiées.

Si le code que vous passez est correct, alors la fonction retourne vrai ; elle retourne faux sinon.

En cas d’erreurs, un tableau des erreurs est présent avec JSHint.errors. Il se compose d’un ensemble d’objets d’erreurs comprenant la localisation de l’erreur ainsi que la cause.

Voici un exemple assez simple demandant la vérification des blocs vides dans le code grâce à l’option noempty. Il vous faut d’abord télécharger et installer le script jshint.js.

<html> 
<head> 
    <title>Test JSHint</title> 
    <script type="text/javascript" src="jshint.js"></script> 
    <script type="text/javascript"> 
 
        var result = JSHINT( "a = 10;\nif ( a == 10 ) {}", 
{noempty:true} ); 
        var erreurs = JSHINT.errors; 
 
        if ( erreurs.length > 0 ) { 
            for ( var i = 0; i < erreurs.length; i++ ) { 
                var erreur = erreurs[ i ]; 
                var...

Documenter votre code avec JSDoc

1. Le principe

JSDoc reprend le concept de la JavaDoc de Java et des annotations. Elle consiste à intégrer dans vos commentaires des marqueurs. Grâce à ces marqueurs, il est alors possible de générer une documentation plus lisible tout en renforçant certains contrôles. Des outils supplémentaires sont capables de mieux comprendre votre code afin d’effectuer des traitements de type compression avec Google’s Closure. Enfin, certains éditeurs comme WebStorm et NetBeans sont capables d’interpréter vos marqueurs et de mieux vous assister à la saisie.

On peut aussi dire que JSDoc est en quelque sorte une extension de JavaScript en termes de typage afin de mieux identifier les valeurs employées.

Pour utiliser JSDoc, vos commentaires doivent être sous la forme :

/** 
Vos commentaires 
*/ 

Attention à ne pas oublier la double étoile en début de commentaire.

Un marqueur commence par @, par exemple @param va désigner un paramètre de fonction.

2. Les marqueurs

a. Déclarations

Le cas le plus simple est l’usage du marqueur type pour désigner la nature d’une variable ou la nature de la valeur retournée par une fonction :

/** @type {Number} */ 
var a = 10; 
 
/** @type {String} */ 
var maChaine = "hello world"; 
 
/** @type {Boolean} */ 
var etat = true; 
 
/** @type {Boolean} */ 
function flag() { 
    return "ok"; 
} 

Grâce au marqueur constant, vous avez la possibilité d’indiquer qu’une variable est en réalité une constante :

/** @constant */ 
var c = 10; 
c++;    // Erreur à l'édition car c ne peut être modifiée 

b. Fonctions

Pour documenter une fonction, vous aurez en général l’usage de @param et @return :

/** 
 * Effectuer une opération binaire 
 * @param {Number} operand1 Un entier 
 * @param {Number} operand2 Un entier 
 * @param {String} operator Une chaîne désignant l'opération 
 * @return {Number} le résultat de l'opération ...

Passage d’un environnement de développement à un environnement de production

1. Tests unitaires

a. Introduction

Lorsque votre code est stable et que vous avez des fonctions et/ou classes critiques, il peut être souhaitable de mettre en place des tests unitaires afin d’en valider le fonctionnement. Cela est d’autant plus important que vous avez des mises à jour à effectuer afin de réduire les problèmes de régression lorsque vous passez dans un environnement de production.

D’un point de vue pratique, il est d’autant plus facile de mettre en place des tests unitaires que vos fonctions et/ou classes à tester sont présentes dans des fichiers JavaScript indépendants de vos pages HTML.

La manière la plus simple pour les tests unitaires est d’évaluer un ensemble d’expression et de valider que le résultat corresponde à un résultat donné. Si ce n’est pas le cas, le test unitaire échoue et le passage en production doit alors être temporisé jusqu’à la résolution du problème.

b. Gestion avec votre propre librairie

Mettre en place votre propre système de tests unitaires n’est pas forcément très complexe. Cela dépend avant tout de la manière dont votre code a été structuré. Vous pouvez par exemple créer autant de pages HTML de test que vous avez de scripts.

Prenons un exemple simple avec un ensemble de fonctions de calcul. Nous supposons que ces fonctions sont présentes dans un fichier indépendant calcul.js. Nous pouvons avoir à l’intérieur ce type de structure :

/* 
 * Module de calcul 
 */ 
var calcul = ( function() { 
 
    var calcul = {}; 
 
    function division( a, b ) { 
        return a / b; 
    } 
 
    function somme( a, b ) { 
        return a + b; 
    } 
 
    calcul.division = division; 
    calcul.somme = somme; 
    return calcul; 
 
} )(); 

Nous avons deux...