Tiêu chuẩn mã hóa JavaScript
JavaScript Tiêu Chuẩn
Phần tiêu đề “JavaScript Tiêu Chuẩn”XOOPS tuân theo các tiêu chuẩn JavaScript hiện đại (ES6+) với sự nhấn mạnh vào khả năng đọc và khả năng bảo trì.
Tổng quan
Phần tiêu đề “Tổng quan”Các tiêu chuẩn XOOPS JavaScript dựa trên:
- ECMAScript 2015+ (ES6 và các tính năng hiện đại)
- Hướng dẫn về phong cách Airbnb JavaScript (đã điều chỉnh)
- Quy ước XOOPS để đảm bảo tính nhất quán
- Tiêu chuẩn tiếp cận (WCAG)
Cấu trúc tệp
Phần tiêu đề “Cấu trúc tệp”Tổ chức tập tin
Phần tiêu đề “Tổ chức tập tin”// 1. File header comment/** * 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. Importsimport { Helper } from './helpers.js';import { API } from './api.js';
// 3. Constantsconst DEFAULT_TIMEOUT = 5000;const API_ENDPOINT = '/api/v1';
// 4. Module setupconst Dashboard = {};
// 5. Private functionsfunction initializeUI() { // ...}
// 6. Public methodsDashboard.init = function () { // ...};
// 7. Exportsexport default Dashboard;Đặt tên tệp
Phần tiêu đề “Đặt tên tệp”// Use lowercase with hyphensdashboard.jsuser-profile.jsform-validator.jsapi-client.js
// React components (PascalCase)UserProfile.jsxFormValidator.jsxDashboard.jsxBiến và hằng
Phần tiêu đề “Biến và hằng”Khai báo biến
Phần tiêu đề “Khai báo biến”// Use const by defaultconst maxRetries = 3;const userName = 'John';
// Use let for variables that changelet currentIndex = 0;
// Avoid var (legacy)// ❌ var oldStyle = true;
// Const objects and arrays can have contents modifiedconst user = { name: 'John' };user.name = 'Jane'; // ✅ OKuser = {}; // ❌ Error
const numbers = [1, 2, 3];numbers.push(4); // ✅ OKnumbers = []; // ❌ ErrorĐặt tên biến
Phần tiêu đề “Đặt tên biến”// Use descriptive namesconst userName = 'John'; // ✅const un = 'John'; // ❌
// Boolean variables should indicate stateconst isActive = true; // ✅const hasPermission = false; // ✅const canEdit = true; // ✅const active = true; // ❌ Unclear
// Arrays should use plural namesconst users = ['John', 'Jane'];const userList = ['John', 'Jane'];const items = [];Hằng số
Phần tiêu đề “Hằng số”// UPPER_SNAKE_CASE for module-level constantsconst API_TIMEOUT = 5000;const MAX_RETRIES = 3;const DEFAULT_PAGE_SIZE = 10;
// camelCase for object properties (even constants)const config = { apiTimeout: 5000, maxRetries: 3, defaultPageSize: 10,};Chức năng
Phần tiêu đề “Chức năng”Khai báo hàm
Phần tiêu đề “Khai báo hàm”// Named functions (preferred for reusability)function validateEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);}
// Arrow functions (preferred for callbacks)const validateEmail = (email) => { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);};
// Short arrow functionsconst isPositive = (num) => num > 0;const double = (x) => x * 2;
// Avoid anonymous function expressions// ❌ const fn = function() {};Đặt tên hàm
Phần tiêu đề “Đặt tên hàm”// Use descriptive verb-based namesfunction getUserById(id) { } // ✅ Describes what it getsfunction validateUserInput(data) { } // ✅ Describes actionfunction formatDate(date) { } // ✅ Describes transformation
// Avoid single letters except in obvious cases (loops)function f(x) { } // ❌function fetch() { } // ❌ Conflicts with globalTham số chức năng
Phần tiêu đề “Tham số chức năng”// Use clear parameter namesfunction addUser(name, email, role = 'user') { // ...}
// Use destructuring for objectsfunction createPost({ title, content, author, published = false }) { // ...}
// Document complex functions/** * Fetch user data from the API * @param {number} userId - The user ID to fetch * @param {Object} options - Optional settings * @param {boolean} options.includeProfile - Include profile data * @returns {Promise<Object>} User data object */async function fetchUser(userId, options = {}) { const { includeProfile = false } = options; // ...}Lớp và đối tượng
Phần tiêu đề “Lớp và đối tượng”Định nghĩa lớp
Phần tiêu đề “Định nghĩa lớp”/** * Represents a user in the system */class User { constructor(name, email) { this.name = name; this.email = email; this.id = null; }
/** * Get user's display name * @returns {string} */ getDisplayName() { return this.name.trim(); }
/** * Validate user email * @returns {boolean} */ isValidEmail() { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email); }}
// Usageconst user = new User('John Doe', 'john@example.com');console.log(user.getDisplayName());Đối tượng Literal
Phần tiêu đề “Đối tượng Literal”// Use object shorthandconst name = 'John';const age = 30;
// Shorthand properties (ES6)const person = { name, age, getInfo() { return `${this.name} is ${this.age} years old`; },};
// Without shorthand (avoid)// const person = {// name: name,// age: age,// getInfo: function() { }// };Định dạng
Phần tiêu đề “Định dạng”Khoảng cách và thụt lề
Phần tiêu đề “Khoảng cách và thụt lề”// Use 2 spaces for indentation (or 4, be consistent)function example() { if (true) { console.log('Indented'); }}
// Spaces around operatorsconst x = 5 + 3; // ✅const y = 5+3; // ❌const z = isDone ? 'yes' : 'no'; // ✅
// No space inside parenthesesif (condition) { } // ✅if ( condition ) { } // ❌
// Space before function bracesfunction test() { } // ✅function test(){ } // ❌Độ dài dòng
Phần tiêu đề “Độ dài dòng”// Maximum 100 characters per line (or 120)// Break long lines logically
// Long stringsconst message = 'This is a very long message that ' + 'continues on the next line';
// Long function callsconst result = myFunction( parameter1, parameter2, parameter3);
// Long conditionalsif (condition1 && condition2 && condition3) { // ...}Dấu chấm phẩy
Phần tiêu đề “Dấu chấm phẩy”// Use semicolonsconst x = 5; // ✅const y = 10;
// Not using semicolons (ASI - Automatic Semicolon Insertion)const x = 5 // ❌ Avoid relying on thisChuỗi
Phần tiêu đề “Chuỗi”Chuỗi ký tự
Phần tiêu đề “Chuỗi ký tự”// Use single quotes for consistencyconst name = 'John'; // ✅
// Or double quotes - just be consistentconst name = "John";
// Use backticks for template literals (interpolation)const greeting = `Hello, ${name}!`; // ✅
// Avoid concatenationconst message = 'Hello ' + name; // ❌const message = `Hello ${name}`; // ✅
// Multi-line stringsconst html = ` <div> <h1>${title}</h1> <p>${content}</p> </div>`;Phương thức mảng
Phần tiêu đề “Phương thức mảng”// Prefer modern array methodsconst 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); // ✅Phá hủy mảng
Phần tiêu đề “Phá hủy mảng”// Extract array elementsconst [first, second, ...rest] = [1, 2, 3, 4, 5];// first = 1, second = 2, rest = [3, 4, 5]
// Skip elementsconst [,, third] = [1, 2, 3];// third = 3
// Use in function parametersfunction processItems([first, second]) { console.log(first, second);}Đối tượng
Phần tiêu đề “Đối tượng”Phá hủy đối tượng
Phần tiêu đề “Phá hủy đối tượng”// Extract object propertiesconst user = { name: 'John', email: 'john@example.com' };const { name, email } = user;
// Rename propertiesconst { name: userName, email: userEmail } = user;
// Default valuesconst { role = 'user' } = user;
// Nested destructuringconst { user: { name, email } } = response;
// Function parametersfunction displayUser({ name, email, role = 'user' }) { console.log(`${name} (${role})`);}Toán tử trải rộng
Phần tiêu đề “Toán tử trải rộng”// Copy arraysconst original = [1, 2, 3];const copy = [...original];
// Merge arraysconst merged = [...arr1, ...arr2];
// Copy objectsconst user = { name: 'John', email: 'john@example.com' };const userCopy = { ...user };
// Merge objectsconst merged = { ...defaults, ...options };
// Update propertiesconst updated = { ...user, email: 'newemail@example.com' };Lập trình không đồng bộ
Phần tiêu đề “Lập trình không đồng bộ”Lời hứa
Phần tiêu đề “Lời hứa”// Basic promiseconst promise = new Promise((resolve, reject) => { if (success) { resolve(result); } else { reject(error); }});
// Promise methodsPromise.all([p1, p2, p3]) .then(results => console.log(results)) .catch(error => console.error(error));
Promise.race([p1, p2]) .then(result => console.log(result));Không đồng bộ/Đang chờ
Phần tiêu đề “Không đồng bộ/Đang chờ”// Preferred for readabilityasync 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; }}
// Usageconst user = await fetchUser(123);
// Multiple operationsasync function loadDashboard() { const users = await fetchUsers(); const posts = await fetchPosts(); const comments = await fetchComments();
return { users, posts, comments };}Bình luận và Tài liệu
Phần tiêu đề “Bình luận và Tài liệu”Bình luận nội tuyến
Phần tiêu đề “Bình luận nội tuyến”// Explain WHY, not WHATconst result = calculateTotal(items, taxRate); // ✅ Why
// ❌ Don't explain obvious codeconst x = 5; // Set x to 5const sum = a + b; // Add a and bBình luận JSDoc
Phần tiêu đề “Bình luận JSDoc”/** * Calculate the total price of items including tax * * @param {Array<Object>} items - Array of items with price property * @param {number} taxRate - Tax rate as decimal (0.1 = 10%) * @returns {number} Total price including tax * @throws {Error} If items is not an array * @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);}Xử lý lỗi
Phần tiêu đề “Xử lý lỗi”Thử/Bắt
Phần tiêu đề “Thử/Bắt”// Always handle errorstry { const result = riskyOperation();} catch (error) { console.error('Operation failed:', error);} finally { cleanup();}
// Be specific with errorstry { const data = JSON.parse(jsonString);} catch (error) { if (error instanceof SyntaxError) { console.error('Invalid JSON'); } else { console.error('Unknown error'); }}Lỗi tùy chỉnh
Phần tiêu đề “Lỗi tùy chỉnh”class ValidationError extends Error { constructor(message) { super(message); this.name = 'ValidationError'; }}
// Usageif (!isValidEmail(email)) { throw new ValidationError(`Invalid email: ${email}`);}Thao tác DOM
Phần tiêu đề “Thao tác DOM”Chọn phần tử
Phần tiêu đề “Chọn phần tử”// Modern methods (preferred)const element = document.querySelector('#my-id');const elements = document.querySelectorAll('.my-class');
// Avoid older methods// const el = document.getElementById('my-id'); // ❌// const els = document.getElementsByClassName('my-class'); // ❌
// Cache elementsconst button = document.querySelector('button');button.addEventListener('click', handler);Xử lý sự kiện
Phần tiêu đề “Xử lý sự kiện”// Use addEventListenerelement.addEventListener('click', (event) => { event.preventDefault(); handleClick();});
// Remove listenerselement.removeEventListener('click', handler);
// Event delegationcontainer.addEventListener('click', (event) => { if (event.target.matches('.item')) { handleItemClick(event.target); }});Cập nhật DOM
Phần tiêu đề “Cập nhật DOM”// Use textContent (safer than innerHTML)element.textContent = 'Safe text'; // ✅
// Use innerHTML only for trusted contentelement.innerHTML = `<b>${escapeHtml(text)}</b>`;
// Class manipulationelement.classList.add('active');element.classList.remove('inactive');element.classList.toggle('disabled');
// Attribute manipulationelement.setAttribute('data-id', userId);const id = element.getAttribute('data-id');element.removeAttribute('disabled');Mẫu mô-đun
Phần tiêu đề “Mẫu mô-đun”Mô-đun ES6
Phần tiêu đề “Mô-đun ES6”// Exportexport const helper = () => { };export default Dashboard;
// Importimport Dashboard from './dashboard.js';import { helper } from './helper.js';import * as utils from './utils.js';Tóm tắt các phương pháp hay nhất
Phần tiêu đề “Tóm tắt các phương pháp hay nhất”- Mặc định sử dụng const
- Sử dụng tên mô tả
- Sử dụng các chức năng mũi tên để gọi lại
- Sử dụng async/await cho lời hứa
- Tài liệu các chức năng phức tạp
- Các phần tử DOM bộ đệm
- Sử dụng sự kiện ủy nhiệm
- Viết hàm thuần túy
- Giữ chức năng tập trung
- Sử dụng var (cũ)
- Sử dụng biến toàn cục
- Tạo các hàm dài (trên 50 dòng)
- Mã tổ sâu
- Sử dụng eval()
- Sử dụng trình xử lý sự kiện nội tuyến
- Để lại console.log() trong quá trình sản xuất
- Tạo rò rỉ bộ nhớ
- Thay đổi thông số hàm
Công cụ và Linting
Phần tiêu đề “Công cụ và Linting”Cấu hình ESLint
Phần tiêu đề “Cấu hình 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" }}Cấu hình đẹp hơn
Phần tiêu đề “Cấu hình đẹp hơn”{ "semi": true, "singleQuote": true, "trailingComma": "es5", "printWidth": 100, "tabWidth": 2}Tài liệu liên quan
Phần tiêu đề “Tài liệu liên quan”- Hướng dẫn CSS
- Quy tắc ứng xử
- Quy trình làm việc đóng góp
- Tiêu chuẩn PHP
#xoops #javascript #es6 #coding-standards #best-practices