Стандарты кодирования JavaScript
Стандарты JavaScript
Заголовок раздела «Стандарты JavaScript»XOOPS следует современным стандартам JavaScript (ES6+) с акцентом на читаемость и поддерживаемость.
Стандарты JavaScript XOOPS основаны на:
- ECMAScript 2015+ (ES6 и современные функции)
- Руководство по стилю JavaScript Airbnb (адаптировано)
- Соглашения XOOPS для согласованности
- Стандарты доступности (WCAG)
Структура файлов
Заголовок раздела «Структура файлов»Организация файлов
Заголовок раздела «Организация файлов»// 1. Заголовочный комментарий файла/** * XOOPS Module - Feature Name * @file Handles user interactions on the dashboard * @author Your Name <email@example.com> * @copyright 2026 XOOPS Project * @license GPL-2.0-or-later */
// 2. Импортыimport { Helper } from './helpers.js';import { API } from './api.js';
// 3. Константыconst DEFAULT_TIMEOUT = 5000;const API_ENDPOINT = '/api/v1';
// 4. Настройка модуляconst Dashboard = {};
// 5. Приватные функцииfunction initializeUI() { // ...}
// 6. Публичные методыDashboard.init = function () { // ...};
// 7. Экспортыexport default Dashboard;Наименование файлов
Заголовок раздела «Наименование файлов»// Используйте нижний регистр с дефисамиdashboard.jsuser-profile.jsform-validator.jsapi-client.js
// React компоненты (PascalCase)UserProfile.jsxFormValidator.jsxDashboard.jsxПеременные и константы
Заголовок раздела «Переменные и константы»Объявление переменных
Заголовок раздела «Объявление переменных»// Используйте const по умолчаниюconst maxRetries = 3;const userName = 'John';
// Используйте let для переменных, которые изменяютсяlet currentIndex = 0;
// Избегайте var (устаревший)// ❌ var oldStyle = true;
// Объекты и массивы const могут иметь изменяемое содержимоеconst user = { name: 'John' };user.name = 'Jane'; // ✅ OKuser = {}; // ❌ Error
const numbers = [1, 2, 3];numbers.push(4); // ✅ OKnumbers = []; // ❌ ErrorИменование переменных
Заголовок раздела «Именование переменных»// Используйте описательные именаconst userName = 'John'; // ✅const un = 'John'; // ❌
// Булевы переменные должны указывать состояниеconst isActive = true; // ✅const hasPermission = false; // ✅const canEdit = true; // ✅const active = true; // ❌ Неясно
// Массивы должны использовать множественные именаconst users = ['John', 'Jane'];const userList = ['John', 'Jane'];const items = [];Константы
Заголовок раздела «Константы»// UPPER_SNAKE_CASE для констант уровня модуляconst API_TIMEOUT = 5000;const MAX_RETRIES = 3;const DEFAULT_PAGE_SIZE = 10;
// camelCase для свойств объектов (даже констант)const config = { apiTimeout: 5000, maxRetries: 3, defaultPageSize: 10,};Функции
Заголовок раздела «Функции»Объявление функций
Заголовок раздела «Объявление функций»// Именованные функции (предпочтительно для переиспользования)function validateEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);}
// Стрелочные функции (предпочтительно для обратных вызовов)const validateEmail = (email) => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);};
// Короткие стрелочные функцииconst isPositive = (num) => num > 0;const double = (x) => x * 2;
// Избегайте анонимных выражений функций// ❌ const fn = function() {};Именование функций
Заголовок раздела «Именование функций»// Используйте описательные имена на основе глаголовfunction getUserById(id) { } // ✅ Описывает то, что она получаетfunction validateUserInput(data) { } // ✅ Описывает действиеfunction formatDate(date) { } // ✅ Описывает преобразование
// Избегайте одиночных букв, кроме очевидных случаев (циклы)function f(x) { } // ❌function fetch() { } // ❌ Конфликтует с глобальнойПараметры функций
Заголовок раздела «Параметры функций»// Используйте четкие имена параметровfunction addUser(name, email, role = 'user') { // ...}
// Используйте деструктуризацию для объектовfunction createPost({ title, content, author, published = false }) { // ...}
// Документируйте сложные функции/** * Получить данные пользователя из API * @param {number} userId - ID пользователя для получения * @param {Object} options - Дополнительные настройки * @param {boolean} options.includeProfile - Включить данные профиля * @returns {Promise<Object>} Объект данных пользователя */async function fetchUser(userId, options = {}) { const { includeProfile = false } = options; // ...}Классы и объекты
Заголовок раздела «Классы и объекты»Определение класса
Заголовок раздела «Определение класса»/** * Представляет пользователя в системе */class User { constructor(name, email) { this.name = name; this.email = email; this.id = null; }
/** * Получить отображаемое имя пользователя * @returns {string} */ getDisplayName() { return this.name.trim(); }
/** * Проверить адрес электронной почты пользователя * @returns {boolean} */ isValidEmail() { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email); }}
// Использованиеconst user = new User('John Doe', 'john@example.com');console.log(user.getDisplayName());Объектные литералы
Заголовок раздела «Объектные литералы»// Используйте сокращение объектовconst name = 'John';const age = 30;
// Сокращенные свойства (ES6)const person = { name, age, getInfo() { return `${this.name} is ${this.age} years old`; },};
// Без сокращения (избегайте)// const person = {// name: name,// age: age,// getInfo: function() { }// };Форматирование
Заголовок раздела «Форматирование»Интервал и отступы
Заголовок раздела «Интервал и отступы»// Используйте 2 пробела для отступа (или 4, будьте согласованны)function example() { if (true) { console.log('Indented'); }}
// Пробелы вокруг операторовconst x = 5 + 3; // ✅const y = 5+3; // ❌const z = isDone ? 'yes' : 'no'; // ✅
// Без пробелов внутри скобокif (condition) { } // ✅if ( condition ) { } // ❌
// Пространство перед скобками функцииfunction test() { } // ✅function test(){ } // ❌Длина строки
Заголовок раздела «Длина строки»// Максимум 100 символов на строку (или 120)// Разбивайте длинные строки логически
// Длинные строкиconst message = 'This is a very long message that ' + 'continues on the next line';
// Долгие вызовы функцийconst result = myFunction( parameter1, parameter2, parameter3);
// Долгие условияif (condition1 && condition2 && condition3) { // ...}Точки с запятой
Заголовок раздела «Точки с запятой»// Используйте точки с запятойconst x = 5; // ✅const y = 10;
// Не использовать точки с запятой (ASI - Automatic Semicolon Insertion)const x = 5 // ❌ Избегайте полагаться на этоСтроковые литералы
Заголовок раздела «Строковые литералы»// Используйте одиночные кавычки для согласованностиconst name = 'John'; // ✅
// Или двойные кавычки - просто будьте согласованныconst name = "John";
// Используйте обратные кавычки для шаблонных литералов (интерполяция)const greeting = `Hello, ${name}!`; // ✅
// Избегайте конкатенацииconst message = 'Hello ' + name; // ❌const message = `Hello ${name}`; // ✅
// Многострочные строкиconst html = ` <div> <h1>${title}</h1> <p>${content}</p> </div>`;Массивы
Заголовок раздела «Массивы»Методы массивов
Заголовок раздела «Методы массивов»// Предпочитайте современные методы массивовconst 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); // ✅Деструктуризация массивов
Заголовок раздела «Деструктуризация массивов»// Извлеките элементы массиваconst [first, second, ...rest] = [1, 2, 3, 4, 5];// first = 1, second = 2, rest = [3, 4, 5]
// Пропустите элементыconst [,, third] = [1, 2, 3];// third = 3
// Используйте в параметрах функцииfunction processItems([first, second]) { console.log(first, second);}Объекты
Заголовок раздела «Объекты»Деструктуризация объектов
Заголовок раздела «Деструктуризация объектов»// Извлеките свойства объектаconst user = { name: 'John', email: 'john@example.com' };const { name, email } = user;
// Переименуйте свойстваconst { name: userName, email: userEmail } = user;
// Значения по умолчаниюconst { role = 'user' } = user;
// Вложенная деструктуризацияconst { user: { name, email } } = response;
// Параметры функцииfunction displayUser({ name, email, role = 'user' }) { console.log(`${name} (${role})`);}Оператор разворота
Заголовок раздела «Оператор разворота»// Копировать массивыconst original = [1, 2, 3];const copy = [...original];
// Объединить массивыconst merged = [...arr1, ...arr2];
// Копировать объектыconst user = { name: 'John', email: 'john@example.com' };const userCopy = { ...user };
// Объединить объектыconst merged = { ...defaults, ...options };
// Обновить свойстваconst updated = { ...user, email: 'newemail@example.com' };Асинхронное программирование
Заголовок раздела «Асинхронное программирование»Обещания
Заголовок раздела «Обещания»// Базовое обещаниеconst promise = new Promise((resolve, reject) => { if (success) { resolve(result); } else { reject(error); }});
// Методы обещанияPromise.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
Заголовок раздела «Async/Await»// Предпочтительно для читаемости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; }}
// Использованиеconst user = await fetchUser(123);
// Несколько операцийasync function loadDashboard() { const users = await fetchUsers(); const posts = await fetchPosts(); const comments = await fetchComments();
return { users, posts, comments };}Комментарии и документация
Заголовок раздела «Комментарии и документация»Встроенные комментарии
Заголовок раздела «Встроенные комментарии»// Объясните ПОЧЕМУ, а не ЧТОconst result = calculateTotal(items, taxRate); // ✅ Почему
// ❌ Не объясняйте очевидный кодconst x = 5; // Set x to 5const sum = a + b; // Add a and bКомментарии JSDoc
Заголовок раздела «Комментарии JSDoc»/** * Рассчитайте общую цену предметов с включением налога * * @param {Array<Object>} items - Массив элементов со свойством цены * @param {number} taxRate - Налоговая ставка в десятичном формате (0.1 = 10%) * @returns {number} Общая цена с включением налога * @throws {Error} Если items не массив * @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);}Обработка ошибок
Заголовок раздела «Обработка ошибок»Try/Catch
Заголовок раздела «Try/Catch»// Всегда обрабатывайте ошибкиtry { const result = riskyOperation();} catch (error) { console.error('Operation failed:', error);} finally { cleanup();}
// Будьте конкретны в отношении ошибокtry { const data = JSON.parse(jsonString);} catch (error) { if (error instanceof SyntaxError) { console.error('Invalid JSON'); } else { console.error('Unknown error'); }}Пользовательские ошибки
Заголовок раздела «Пользовательские ошибки»class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; }}
// Использованиеif (!isValidEmail(email)) { throw new ValidationError(`Invalid email: ${email}`);}Манипуляция DOM
Заголовок раздела «Манипуляция DOM»Выбор элементов
Заголовок раздела «Выбор элементов»// Современные методы (предпочтительно)const element = document.querySelector('#my-id');const elements = document.querySelectorAll('.my-class');
// Избегайте старых методов// const el = document.getElementById('my-id'); // ❌// const els = document.getElementsByClassName('my-class'); // ❌
// Кэшируйте элементыconst button = document.querySelector('button');button.addEventListener('click', handler);Обработка событий
Заголовок раздела «Обработка событий»// Используйте addEventListenerelement.addEventListener('click', (event) => { event.preventDefault(); handleClick();});
// Удалите слушателейelement.removeEventListener('click', handler);
// Делегирование событийcontainer.addEventListener('click', (event) => { if (event.target.matches('.item')) { handleItemClick(event.target); }});Обновления DOM
Заголовок раздела «Обновления DOM»// Используйте textContent (безопаснее, чем innerHTML)element.textContent = 'Safe text'; // ✅
// Используйте innerHTML только для доверенного контентаelement.innerHTML = `<b>${escapeHtml(text)}</b>`;
// Манипуляция классамиelement.classList.add('active');element.classList.remove('inactive');element.classList.toggle('disabled');
// Манипуляция атрибутамиelement.setAttribute('data-id', userId);const id = element.getAttribute('data-id');element.removeAttribute('disabled');Паттерн модулей
Заголовок раздела «Паттерн модулей»ES6 модули
Заголовок раздела «ES6 модули»// Экспортexport const helper = () => { };export default Dashboard;
// Импортimport Dashboard from './dashboard.js';import { helper } from './helper.js';import * as utils from './utils.js';Сводка лучших практик
Заголовок раздела «Сводка лучших практик»Делайте
Заголовок раздела «Делайте»- Используйте const по умолчанию
- Используйте описательные имена
- Используйте стрелочные функции для обратных вызовов
- Используйте async/await для обещаний
- Документируйте сложные функции
- Кэшируйте элементы DOM
- Используйте делегирование событий
- Пишите чистые функции
- Держите функции сосредоточенными
Не делайте
Заголовок раздела «Не делайте»- Не используйте var (устаревший)
- Не используйте глобальные переменные
- Не создавайте длинные функции (более 50 строк)
- Не вложите глубоко код
- Не используйте eval()
- Не используйте встроенные обработчики событий
- Не оставляйте console.log() в продакшене
- Не создавайте утечки памяти
- Не мутируйте параметры функции
Инструменты и линтинг
Заголовок раздела «Инструменты и линтинг»Конфигурация ESLint
Заголовок раздела «Конфигурация 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" }}Конфигурация Prettier
Заголовок раздела «Конфигурация Prettier»{ "semi": true, "singleQuote": true, "trailingComma": "es5", "printWidth": 100, "tabWidth": 2}Связанная документация
Заголовок раздела «Связанная документация»- Рекомендации CSS
- Кодекс поведения
- Рабочий процесс участия
- Стандарты PHP
#xoops #javascript #es6 #coding-standards #best-practices