Normes de Codage JavaScript
Normes JavaScript
Section intitulée « Normes JavaScript »XOOPS suit les normes JavaScript modernes (ES6+) en mettant l’accent sur la lisibilité et la maintenabilité.
Les normes JavaScript de XOOPS sont basées sur:
- ECMAScript 2015+ (ES6 et fonctionnalités modernes)
- Guide de Style JavaScript d’Airbnb (adapté)
- Conventions XOOPS pour la cohérence
- Normes d’accessibilité (WCAG)
Structure des Fichiers
Section intitulée « Structure des Fichiers »Organisation des Fichiers
Section intitulée « Organisation des Fichiers »// 1. Commentaire d'en-tête du fichier/** * Module XOOPS - Nom de la Fonctionnalité * @file Gère les interactions utilisateur sur le tableau de bord * @author Votre Nom <email@example.com> * @copyright 2026 Projet XOOPS * @license GPL-2.0-or-later */
// 2. Importsimport { Helper } from './helpers.js';import { API } from './api.js';
// 3. Constantesconst DEFAULT_TIMEOUT = 5000;const API_ENDPOINT = '/api/v1';
// 4. Configuration du moduleconst Dashboard = {};
// 5. Fonctions privéesfunction initializeUI() { // ...}
// 6. Méthodes publiquesDashboard.init = function () { // ...};
// 7. Exportsexport default Dashboard;Nommage des Fichiers
Section intitulée « Nommage des Fichiers »// Utilisez des minuscules avec des tiretsdashboard.jsuser-profile.jsform-validator.jsapi-client.js
// Composants React (PascalCase)UserProfile.jsxFormValidator.jsxDashboard.jsxVariables et Constantes
Section intitulée « Variables et Constantes »Déclaration de Variables
Section intitulée « Déclaration de Variables »// Utilisez const par défautconst maxRetries = 3;const userName = 'John';
// Utilisez let pour les variables qui changentlet currentIndex = 0;
// Évitez var (legacy)// ❌ var oldStyle = true;
// Les objets et tableaux const peuvent avoir leur contenu modifiéconst user = { name: 'John' };user.name = 'Jane'; // ✅ OKuser = {}; // ❌ Erreur
const numbers = [1, 2, 3];numbers.push(4); // ✅ OKnumbers = []; // ❌ ErreurNommage des Variables
Section intitulée « Nommage des Variables »// Utilisez des noms descriptifsconst userName = 'John'; // ✅const un = 'John'; // ❌
// Les variables booléennes doivent indiquer l'étatconst isActive = true; // ✅const hasPermission = false; // ✅const canEdit = true; // ✅const active = true; // ❌ Peu clair
// Les tableaux doivent utiliser des noms au plurielconst users = ['John', 'Jane'];const userList = ['John', 'Jane'];const items = [];Constantes
Section intitulée « Constantes »// UPPER_SNAKE_CASE pour les constantes de niveau moduleconst API_TIMEOUT = 5000;const MAX_RETRIES = 3;const DEFAULT_PAGE_SIZE = 10;
// camelCase pour les propriétés d'objet (même les constantes)const config = { apiTimeout: 5000, maxRetries: 3, defaultPageSize: 10,};Fonctions
Section intitulée « Fonctions »Déclaration de Fonction
Section intitulée « Déclaration de Fonction »// Fonctions nommées (préférées pour la réutilisabilité)function validateEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);}
// Fonctions fléchées (préférées pour les callbacks)const validateEmail = (email) => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);};
// Fonctions fléchées courtesconst isPositive = (num) => num > 0;const double = (x) => x * 2;
// Évitez les expressions de fonction anonyme// ❌ const fn = function() {};Nommage des Fonctions
Section intitulée « Nommage des Fonctions »// Utilisez des noms basés sur des verbes descriptifsfunction getUserById(id) { } // ✅ Décrit ce qu'il récupèrefunction validateUserInput(data) { } // ✅ Décrit l'actionfunction formatDate(date) { } // ✅ Décrit la transformation
// Évitez les lettres uniques sauf dans les cas évidents (boucles)function f(x) { } // ❌function fetch() { } // ❌ Conflit avec la globaleParamètres de Fonction
Section intitulée « Paramètres de Fonction »// Utilisez des noms de paramètres clairsfunction addUser(name, email, role = 'user') { // ...}
// Utilisez la déstructuration pour les objetsfunction createPost({ title, content, author, published = false }) { // ...}
// Documentez les fonctions complexes/** * Récupère les données utilisateur de l'API * @param {number} userId - L'ID utilisateur à récupérer * @param {Object} options - Paramètres optionnels * @param {boolean} options.includeProfile - Inclure les données de profil * @returns {Promise<Object>} Objet de données utilisateur */async function fetchUser(userId, options = {}) { const { includeProfile = false } = options; // ...}Classes et Objets
Section intitulée « Classes et Objets »Définition de Classe
Section intitulée « Définition de Classe »/** * Représente un utilisateur dans le système */class User { constructor(name, email) { this.name = name; this.email = email; this.id = null; }
/** * Obtenir le nom d'affichage de l'utilisateur * @returns {string} */ getDisplayName() { return this.name.trim(); }
/** * Valider l'email de l'utilisateur * @returns {boolean} */ isValidEmail() { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email); }}
// Utilisationconst user = new User('John Doe', 'john@example.com');console.log(user.getDisplayName());Littéraux d’Objet
Section intitulée « Littéraux d’Objet »// Utilisez l'abréviation d'objetconst name = 'John';const age = 30;
// Propriétés abrégées (ES6)const person = { name, age, getInfo() { return `${this.name} is ${this.age} years old`; },};
// Sans abréviation (à éviter)// const person = {// name: name,// age: age,// getInfo: function() { }// };Formatage
Section intitulée « Formatage »Espacement et Indentation
Section intitulée « Espacement et Indentation »// Utilisez 2 espaces pour l'indentation (ou 4, soyez cohérent)function example() { if (true) { console.log('Indented'); }}
// Espaces autour des opérateursconst x = 5 + 3; // ✅const y = 5+3; // ❌const z = isDone ? 'yes' : 'no'; // ✅
// Pas d'espace à l'intérieur des parenthèsesif (condition) { } // ✅if ( condition ) { } // ❌
// Espace avant les accolades de fonctionfunction test() { } // ✅function test(){ } // ❌Longueur des Lignes
Section intitulée « Longueur des Lignes »// Maximum 100 caractères par ligne (ou 120)// Casser les longues lignes logiquement
// Longues chaînesconst message = 'This is a very long message that ' + 'continues on the next line';
// Appels de fonction longsconst result = myFunction( parameter1, parameter2, parameter3);
// Conditionnelles longuesif (condition1 && condition2 && condition3) { // ...}Points-Virgules
Section intitulée « Points-Virgules »// Utilisez des points-virgulesconst x = 5; // ✅const y = 10;
// Ne pas utiliser de points-virgules (ASI - Insertion Automatique de Points-Virgules)const x = 5 // ❌ À éviterChaînes de Caractères
Section intitulée « Chaînes de Caractères »Littéraux de Chaîne
Section intitulée « Littéraux de Chaîne »// Utilisez des guillemets simples pour la cohérenceconst name = 'John'; // ✅
// Ou des guillemets doubles - soyez juste cohérentconst name = "John";
// Utilisez les backticks pour les littéraux de modèle (interpolation)const greeting = `Hello, ${name}!`; // ✅
// Évitez la concaténationconst message = 'Hello ' + name; // ❌const message = `Hello ${name}`; // ✅
// Chaînes multi-lignesconst html = ` <div> <h1>${title}</h1> <p>${content}</p> </div>`;Tableaux
Section intitulée « Tableaux »Méthodes de Tableau
Section intitulée « Méthodes de Tableau »// Préférez les méthodes de tableau modernesconst numbers = [1, 2, 3, 4, 5];
// Mapconst doubled = numbers.map(n => n * 2); // ✅// for (let i = 0; i < numbers.length; i++) { } // ❌
// Filterconst evens = numbers.filter(n => n % 2 === 0); // ✅
// Reduceconst sum = numbers.reduce((acc, n) => acc + n, 0); // ✅
// Findconst first = numbers.find(n => n > 3); // ✅
// Some/Everyconst hasEven = numbers.some(n => n % 2 === 0); // ✅const allPositive = numbers.every(n => n > 0); // ✅Déstructuration de Tableau
Section intitulée « Déstructuration de Tableau »// Extraire les éléments du tableauconst [first, second, ...rest] = [1, 2, 3, 4, 5];// first = 1, second = 2, rest = [3, 4, 5]
// Ignorer les élémentsconst [,, third] = [1, 2, 3];// third = 3
// Utiliser dans les paramètres de fonctionfunction processItems([first, second]) { console.log(first, second);}Déstructuration d’Objet
Section intitulée « Déstructuration d’Objet »// Extraire les propriétés d'objetconst user = { name: 'John', email: 'john@example.com' };const { name, email } = user;
// Renommer les propriétésconst { name: userName, email: userEmail } = user;
// Valeurs par défautconst { role = 'user' } = user;
// Déstructuration imbriquéeconst { user: { name, email } } = response;
// Paramètres de fonctionfunction displayUser({ name, email, role = 'user' }) { console.log(`${name} (${role})`);}Opérateur de Propagation
Section intitulée « Opérateur de Propagation »// Copier des tableauxconst original = [1, 2, 3];const copy = [...original];
// Fusionner des tableauxconst merged = [...arr1, ...arr2];
// Copier des objetsconst user = { name: 'John', email: 'john@example.com' };const userCopy = { ...user };
// Fusionner des objetsconst merged = { ...defaults, ...options };
// Mettre à jour les propriétésconst updated = { ...user, email: 'newemail@example.com' };Programmation Asynchrone
Section intitulée « Programmation Asynchrone »Promises
Section intitulée « Promises »// Promise basiqueconst promise = new Promise((resolve, reject) => { if (success) { resolve(result); } else { reject(error); }});
// Méthodes PromisePromise.all([p1, p2, p3]) .then(results => console.log(results)) .catch(error => console.error(error));
Promise.race([p1, p2]) .then(result => console.log(result));Async/Await
Section intitulée « Async/Await »// Préféré pour la lisibilitéasync function fetchUser(userId) { try { const response = await fetch(`/api/users/${userId}`); if (!response.ok) throw new Error('User not found'); const data = await response.json(); return data; } catch (error) { console.error('Failed to fetch user:', error); throw error; }}
// Utilisationconst user = await fetchUser(123);
// Opérations multiplesasync function loadDashboard() { const users = await fetchUsers(); const posts = await fetchPosts(); const comments = await fetchComments();
return { users, posts, comments };}Commentaires et Documentation
Section intitulée « Commentaires et Documentation »Commentaires Intégrés
Section intitulée « Commentaires Intégrés »// Expliquez POURQUOI, pas QUOIconst result = calculateTotal(items, taxRate); // ✅ Pourquoi
// ❌ N'expliquez pas le code évidentconst x = 5; // Définir x à 5const sum = a + b; // Ajouter a et bCommentaires JSDoc
Section intitulée « Commentaires JSDoc »/** * Calcule le prix total des articles incluant la taxe * * @param {Array<Object>} items - Tableau d'articles avec propriété price * @param {number} taxRate - Taux de taxe comme décimal (0.1 = 10%) * @returns {number} Prix total incluant la taxe * @throws {Error} Si les articles ne forment pas un tableau * @example * const total = calculateTotal( * [{ price: 100 }, { price: 50 }], * 0.1 * ); * console.log(total); // 165 */function calculateTotal(items, taxRate = 0) { if (!Array.isArray(items)) { throw new Error('Items must be an array'); }
const subtotal = items.reduce((sum, item) => sum + item.price, 0); return subtotal * (1 + taxRate);}Gestion des Erreurs
Section intitulée « Gestion des Erreurs »Try/Catch
Section intitulée « Try/Catch »// Gérez toujours les erreurstry { const result = riskyOperation();} catch (error) { console.error('Operation failed:', error);} finally { cleanup();}
// Soyez spécifique avec les erreurstry { const data = JSON.parse(jsonString);} catch (error) { if (error instanceof SyntaxError) { console.error('Invalid JSON'); } else { console.error('Unknown error'); }}Erreurs Personnalisées
Section intitulée « Erreurs Personnalisées »class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; }}
// Utilisationif (!isValidEmail(email)) { throw new ValidationError(`Invalid email: ${email}`);}Manipulation du DOM
Section intitulée « Manipulation du DOM »Sélection des Éléments
Section intitulée « Sélection des Éléments »// Méthodes modernes (préférées)const element = document.querySelector('#my-id');const elements = document.querySelectorAll('.my-class');
// Évitez les méthodes plus anciennes// const el = document.getElementById('my-id'); // ❌// const els = document.getElementsByClassName('my-class'); // ❌
// Mettez en cache les élémentsconst button = document.querySelector('button');button.addEventListener('click', handler);Gestion des Événements
Section intitulée « Gestion des Événements »// Utilisez addEventListenerelement.addEventListener('click', (event) => { event.preventDefault(); handleClick();});
// Supprimez les écouteurselement.removeEventListener('click', handler);
// Délégation d'événementcontainer.addEventListener('click', (event) => { if (event.target.matches('.item')) { handleItemClick(event.target); }});Mises à Jour du DOM
Section intitulée « Mises à Jour du DOM »// Utilisez textContent (plus sûr que innerHTML)element.textContent = 'Safe text'; // ✅
// Utilisez innerHTML uniquement pour le contenu de confianceelement.innerHTML = `<b>${escapeHtml(text)}</b>`;
// Manipulation des classeselement.classList.add('active');element.classList.remove('inactive');element.classList.toggle('disabled');
// Manipulation des attributselement.setAttribute('data-id', userId);const id = element.getAttribute('data-id');element.removeAttribute('disabled');Motif de Module
Section intitulée « Motif de Module »Modules ES6
Section intitulée « Modules ES6 »// Exportexport const helper = () => { };export default Dashboard;
// Importimport Dashboard from './dashboard.js';import { helper } from './helper.js';import * as utils from './utils.js';Résumé des Meilleures Pratiques
Section intitulée « Résumé des Meilleures Pratiques »- Utilisez const par défaut
- Utilisez des noms descriptifs
- Utilisez les fonctions fléchées pour les callbacks
- Utilisez async/await pour les promises
- Documentez les fonctions complexes
- Mettez en cache les éléments DOM
- Utilisez la délégation d’événement
- Écrivez des fonctions pures
- Gardez les fonctions concentrées
À Éviter
Section intitulée « À Éviter »- Utilisez var (legacy)
- Utilisez les variables globales
- Créez des fonctions longues (plus de 50 lignes)
- Imbriquez le code profondément
- Utilisez eval()
- Utilisez les gestionnaires d’événement intégrés
- Laissez console.log() en production
- Créez des fuites mémoire
- Mutez les paramètres de fonction
Outils et Linting
Section intitulée « Outils et Linting »Configuration ESLint
Section intitulée « Configuration ESLint »{ "env": { "browser": true, "es2021": true, "node": true }, "extends": ["eslint:recommended"], "rules": { "indent": ["error", 2], "quotes": ["error", "single"], "semi": ["error", "always"], "no-var": "error", "prefer-const": "error" }}Configuration Prettier
Section intitulée « Configuration Prettier »{ "semi": true, "singleQuote": true, "trailingComma": "es5", "printWidth": 100, "tabWidth": 2}Documentation Connexe
Section intitulée « Documentation Connexe »- Directives CSS
- Code de Conduite
- Flux de Contribution
- Normes PHP
#xoops #javascript #es6 #coding-standards #best-practices