Bien démarrer vos projets
Choisir votre environnement de développement
1. Introduction
JavaScript a longtemps été en manque d’EDI (Environnement de Développement Intégré). La plupart du temps, les développeurs se contentaient d’une édition avec un simple éditeur de texte, en se focalisant sur des assistants de pages HTML/CSS en oubliant JavaScript. L’évolution de ce 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 de code se sont adaptés et offrent maintenant des environnements adaptés à JavaScript. Il est bien sûr toujours possible d’utiliser un éditeur de texte généraliste (comme Notepad++, vi, Emacs, etc.) et travailler avec, mais c’est souvent se priver d’assistants précieux spécifiques à JavaScript offrant 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, etc.).
-
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 séquence car tous les éditeurs/outils ne la supportent pas correctement.
La coloration syntaxique et la vérification syntaxique sont liées. Le gain de temps peut être important de par l’usage conséquent de parenthèses et d’accolades en JavaScript. Les imbrications de fonctions et d’objets peuvent rendre la syntaxe moins 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...
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 JavaScript, l’objectif étant de maintenir l’un ou l’autre plus simplement en réduisant les effets de bord (modifier une partie en altérant l’autre).
Voici un exemple peu correct qui affiche pourtant bien la date au moment de l’affichage de la page.
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Bonjour</h1>
<script>
document.writeln( "Il est " + new Date() );
</script>
</body>
</html>
Le code JavaScript est ici 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 qui est en HTML et le code de traitement qui est en JavaScript.
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 (Document Object Model) permet d’ajouter le résultat (cf. chapitre...
Portée des variables et fonctions
1. Portée des variables
Lorsque vous déclarez une variable, cette dernière n’est « visible » qu’à certains endroits. Lorsque votre variable est déclarée en dehors de toute fonction, sa portée est dite globale, elle est donc accessible 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 facilement 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é (et donc de maintenance d’un code) mais également en termes de performance.
Concernant la qualité, plus vous aurez de déclarations dans l’espace de noms global et plus vous aurez de 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 dont vous ne maîtrisez pas le contenu. 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.
let i = 0;
let j = 0;
// Version globale
let test1 = function() {
for ( i = 0; i < 1000000; i++ ) {
j += j;
}
}
// Version locale
let test2 = function() {
let j = 0;
for ( let i = 0; i < 1000000; i++ ) {
j += j;
}
}
let tests = [ test1, test2 ];
for ( let n = 0; n < tests.length; n++ ) {
let init = new Date().getMilliseconds();
tests[ n ]();
alert(...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 :
let a = null;
let b = a || 10;
alert( b );
Dans notre exemple, nous avons initialisé la variable a à null (donc implicitement à « faux »), la variable b reçoit donc la seule valeur qui est vraie grâce à l’opérateur ||, 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 de fonction a qui peut ou ne peut 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 ) {
let defConfig = {
couleur : "blue",
font : "arial"
};
config = config || defConfig;
let couleur = config.couleur || defConfig.couleur;
let 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...
Passage au mode strict
Usage
Le mode strict est une nouveauté de la norme ECMAScript 5 (supportée par Chrome/Edge/FireFox), 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 types de code 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 aussi parfaitement compatible avec les navigateurs ne gérant pas ce mode (une chaîne seule est une expression n’ayant aucun effet).
Exemple d’une fonction en mode strict :
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function test() {
aa = 10;
}...Analyseurs de code
1. JSHint
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 ou un répertoire pour tout analyser.
-
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.
Pour installer JSHint :
npm install -g jshint
Si, par exemple, nous avons un répertoire CH1 contenant tous nos scripts et un répertoire node_modules contenant nos librairies externes, nous allons en ligne de commande nous positionner dans le répertoire parent de CH1 puis utiliser cette instruction :
jshint CH1 --exclude .\CH1\node_modules...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 les 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 VSCode ou WebStorm 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 constante :
// @ts-check
/** @type {number} */
let a = 10;
/** @type {string} */
let maChaine = "hello world";
/** @type {boolean} */
let etat = true;
/** @type {number} */
const aa = 10;
Dans l’exemple ci-dessus, nous vérifions que les types primitifs (en minuscule) number (nombre), string (chaîne), boolean (booléen) correspondent bien à nos valeurs.
b. Fonctions
Pour documenter une fonction, vous aurez en général l’usage de @param et @return :
// @ts-check
/**
* Effectuer une opération binaire
* @param {number} operand1 Un entier
* @param {number} operand2 Un entier
* @param...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 des classes critiques, il peut être souhaitable de mettre en place des tests unitaires afin d’en valider le fonctionnement et de limiter le problème des « régresssions » suite à des mises à jour.
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 :
let calcul = ( function() {
let calcul = {};
/**
* @param a {number}
* @param b {number}
* @return {number}
*/
function division( a, b ) {
return a / b;
}
/**
* @param a {number}
* @param b {number}
* @return {number}
*/
function somme(...S’accompagner d’une Intelligence Artificielle (IA)
1. Principes
Les LLM (Large Language Model) principaux comme ChatGPT ont été massivement entraînés avec du code informatique, ce qui peut rendre la correction de code, voire la génération de certains blocs de code, plus rapide. Il est théoriquement possible de produire des applications complètes avec du JavaScript mais à vos risques et périls, car un LLM a surtout une approche statistique et, en cas de bug ou de problème, il ne vous sera pas toujours d’un grand secours.
2. Gemini CLI
Gemini CLI (https://github.com/google-gemini/gemini-cli) est un agent IA open source reposant sur l’IA Gemini et Google. Vous disposez d’un assistant en ligne de commande pour vous aider à gérer votre code (JavaScript/HTML/CSS…).
Nous pouvons installer cet agent grâce à NPM avec :
npm install -g @google/gemini-cli
Une fois installé, vous pouvez interroger votre agent IA par la ligne de commande gemini, et cela dans votre répertoire de travail. Par défaut, vous disposez d’un usage gratuit pour 100 requêtes par jour. Au premier démarrage de la commande, ce dernier va se connecter à votre compte, sinon vous devrez obtenir une clé d’usage via https://aistudio.google.com/apikey ; cette clé devra être associée à une variable d’environnement GEMINI_API_KEY.
Lorsque vous avez exécuté gemini, il vous reste à demander à l’agent de vous éclairer sur tel ou tel domaine via un prompt. Il dispose d’un accès à vos fichiers, par exemple en se plaçant dans un répertoire modules contenant le fichier calcul.js.
Il est possible de demander à l’IA une explication sur le rôle de ce fichier comme :
Le fichier calcul.js est un module JavaScript qui fournit
des fonctions de calcul de base.
En résumé, il sert à :
1. Définir des opérations mathématiques : Il contient une fonction somme
pour l'addition et une fonction division pour la division.
2. Gérer les erreurs : La fonction division inclut une sécurité qui
empêche...