Aller au contenu principal

Module JS.10 – Bonnes pratiques

Objectif

Appliquer les bonnes pratiques JavaScript : scope, immutabilité, modularisation, et conventions pour créer du code professionnel et maintenable.

Théorie

Scope (Portée)

Scope global

Variables déclarées en dehors de toute fonction.

const globale = "Je suis globale";

function test() {
console.log(globale); // Accessible
}

Problème : Pollution de l'espace de noms global.

Scope de fonction

Variables déclarées dans une fonction.

function test() {
const locale = "Je suis locale";
console.log(locale); // Accessible
}

console.log(locale); // Erreur : non accessible

Scope de bloc

Variables déclarées avec let ou const dans un bloc.

if (true) {
const bloc = "Je suis dans un bloc";
console.log(bloc); // Accessible
}

console.log(bloc); // Erreur : non accessible

Hoisting

var : Hoisted et initialisé à undefined

console.log(x);  // undefined (pas d'erreur)
var x = 5;

let/const : Hoisted mais pas initialisé (Temporal Dead Zone)

console.log(x);  // Erreur : Cannot access before initialization
let x = 5;

function : Hoisted complètement

test();  // Fonctionne

function test() {
console.log("Test");
}

Immutabilité

Éviter de modifier les données existantes, créer de nouvelles à la place.

Pourquoi l'immutabilité ?

  • Prédictibilité
  • Évite les bugs de mutation
  • Facilite le débogage
  • Compatible avec React, Redux

Techniques

Copies superficielles :

const original = { nom: "Jean", age: 30 };

// Spread operator
const copie = { ...original };

// Object.assign
const copie2 = Object.assign({}, original);

Copies profondes :

// JSON (limité aux types JSON)
const copieProfonde = JSON.parse(JSON.stringify(original));

// Structured Clone (moderne)
const copieProfonde2 = structuredClone(original);

// Bibliothèque (lodash)
const copieProfonde3 = _.cloneDeep(original);

Tableaux immutables :

const nombres = [1, 2, 3];

// ❌ Mutation
nombres.push(4); // Modifie l'original

// ✅ Immutable
const nouveaux = [...nombres, 4]; // Nouveau tableau
const sansPremier = nombres.slice(1); // Nouveau tableau
const doubles = nombres.map(n => n * 2); // Nouveau tableau

Modularisation

Organiser le code en modules réutilisables.

Modules ES6

Export :

// math.js
export function additionner(a, b) {
return a + b;
}

export const PI = 3.14159;

export default function multiplier(a, b) {
return a * b;
}

Import :

// app.js
import multiplier, { additionner, PI } from './math.js';

// Import avec alias
import { additionner as add } from './math.js';

// Import tout
import * as math from './math.js';
math.additionner(1, 2);

CommonJS (Node.js)

// math.js
exports.additionner = function(a, b) {
return a + b;
};

module.exports = {
multiplier: function(a, b) {
return a * b;
}
};

// app.js
const { additionner } = require('./math');
const math = require('./math');

Conventions de nommage

Variables et fonctions : camelCase

const nomUtilisateur = "Jean";
function calculerMoyenne() {}

Classes : PascalCase

class Personne {}
class GestionnaireUtilisateurs {}

Constantes : UPPER_SNAKE_CASE

const MAX_SIZE = 100;
const API_URL = "https://api.exemple.com";

Privé (convention) : _underscore

class Personne {
_agePrive = 30; // Convention (pas vraiment privé)
}

Code propre

Noms descriptifs

// ❌ Mauvais
const d = new Date();
function calc(a, b) {}

// ✅ Bon
const dateActuelle = new Date();
function calculerMoyenne(nombres) {}

Fonctions courtes et focalisées

// ❌ Mauvais : fait trop de choses
function traiterDonnees(donnees) {
// Validation
// Transformation
// Sauvegarde
// Envoi email
// ...
}

// ✅ Bon : une responsabilité
function validerDonnees(donnees) {}
function transformerDonnees(donnees) {}
function sauvegarderDonnees(donnees) {}

DRY (Don't Repeat Yourself)

// ❌ Répétition
function calculerPrixTTC1(prix) {
return prix * 1.20;
}
function calculerPrixTTC2(prix) {
return prix * 1.20;
}

// ✅ Réutilisable
const TAUX_TVA = 1.20;
function calculerPrixTTC(prix) {
return prix * TAUX_TVA;
}

Commentaires utiles

// ❌ Mauvais : explique le "comment"
// Incrémente i de 1
i++;

// ✅ Bon : explique le "pourquoi"
// Réinitialise le compteur pour le prochain lot
i = 0;

Linting et formatage

ESLint : Détecte les erreurs et problèmes de style

{
"rules": {
"no-var": "error",
"prefer-const": "error",
"no-console": "warn"
}
}

Prettier : Formate le code automatiquement

Performance

Éviter les opérations coûteuses

// ❌ Mauvais : recalcul à chaque fois
function calculerTotal(items) {
return items
.filter(i => i.actif)
.map(i => i.prix)
.reduce((sum, p) => sum + p, 0);
}

// ✅ Bon : cache si possible
const cache = new Map();
function calculerTotal(items) {
const cle = JSON.stringify(items);
if (cache.has(cle)) {
return cache.get(cle);
}
const total = items
.filter(i => i.actif)
.map(i => i.prix)
.reduce((sum, p) => sum + p, 0);
cache.set(cle, total);
return total;
}

Éviter les fuites mémoire

// Nettoyer les event listeners
const bouton = document.getElementById('btn');
bouton.addEventListener('click', handler);

// Plus tard
bouton.removeEventListener('click', handler);

// Nettoyer les timers
const timerId = setInterval(() => {}, 1000);
clearInterval(timerId);

Exercice

  1. Scope

    • Testez les différents scopes
    • Comprenez le hoisting
    • Évitez la pollution globale
  2. Immutabilité

    • Créez des copies au lieu de mutations
    • Utilisez spread operator
    • Testez les copies profondes
  3. Modularisation

    • Créez des modules ES6
    • Organisez votre code
    • Importez/exportez correctement
  4. Conventions

    • Appliquez les conventions de nommage
    • Refactorisez du code existant
    • Améliorez la lisibilité
  5. Code propre

    • Refactorisez selon les principes
    • Éliminez la duplication
    • Améliorez les noms

Quiz

  1. Quel est le scope de let et const ?

    • Global
    • Bloc
    • Fonction
  2. Que fait le spread operator avec les objets ?

    • Modifie l'original
    • Crée une copie
    • Supprime les propriétés
  3. Comment exporter une fonction en ES6 ?

    • exports.function
    • export function
    • module.exports
  4. Quelle convention pour les constantes ?

    • camelCase
    • UPPER_SNAKE_CASE
    • PascalCase
  5. Que signifie DRY ?

    • Don't Repeat Yourself
    • Don't Repeat Yourself
    • Do Repeat Yourself

Mini défi

Mission : Refactoriser un projet selon les bonnes pratiques

Prenez un projet JavaScript existant (ou créez-en un) et refactorisez-le :

Améliorations à apporter :

  1. Modularisation

    • Séparez en modules ES6
    • Organisez par fonctionnalité
    • Importez/exportez correctement
  2. Immutabilité

    • Remplacez les mutations par des copies
    • Utilisez spread operator
    • Créez de nouvelles structures au lieu de modifier
  3. Scope et variables

    • Utilisez const par défaut
    • Évitez var
    • Minimisez le scope global
  4. Code propre

    • Noms descriptifs
    • Fonctions courtes et focalisées
    • Éliminez la duplication (DRY)
  5. Conventions

    • Respectez les conventions de nommage
    • Commentaires utiles
    • Structure claire

Critères :

  • ✅ Code modulaire et organisé
  • ✅ Immutabilité respectée
  • ✅ Conventions appliquées
  • ✅ Code propre et maintenable
  • ✅ Documentation appropriée

Objectif : Appliquer toutes les bonnes pratiques pour créer du code professionnel et maintenable.


Validation : Vous pouvez passer au module suivant quand votre code respecte les bonnes pratiques et est bien organisé.