Style - How to write meaningful comments
The best code is self-explanatory. Before writing a comment, ask yourself: "Can I make this code clearer instead?”
// Bad: Code needs explanation
const d = u.filter(x => x.a > 18); // get adults
// Good: Code explains itself
const adults = users.filter(user => user.age > 18);
Well-named variables, functions, and clear logic eliminate most needs for comments. If your code requires extensive comments to be understood, it's probably too complex.
<aside> 💡
A good programmer should do everything in their power to make what they write simple for other programmers to use and comprehend.
</aside>
JavaScript has two comment styles. Use each appropriately:
//)Best for short, single-line explanations:
const TAX_RATE = 0.21; // Dutch VAT rate
// API expects timestamps in seconds, not milliseconds
const timestamp = Date.now() / 1000;
const price = calculatePrice(item); // Includes tax and shipping
/* */)Best for multi-line explanations or function documentation:
/*
* This function uses a binary search algorithm for performance.
* Input array must be sorted in ascending order.
* Returns -1 if element is not found.
*/
function binarySearch(array, target) {
// Implementation
}
/*
* IMPORTANT: Do not modify this regex without testing against:
* - International phone numbers
* - Numbers with extensions
* - Mobile vs landline formats
*/
const phoneRegex = /^\\+?[\\d\\s()-]+$/;
When to use block comments:
When to use inline comments:
// Debugging: temporarily disable validation
// if (!isValid(data)) {
// throw new Error('Invalid data');
// }
/*
Keeping this old implementation for reference
function oldApproach() {
// ...
}
*/
<aside> ⚠️
Don't leave commented-out code in production. Use version control (Git) to track old code instead. Commented code clutters your files and confuses other developers.
</aside>
Comments explain why, not what. Your code already shows what it does: comments should explain the reasoning behind decisions.
// Bad: Explaining what (obvious from code)
// Loop through users
for (const user of users) {
// Add user to active list
activeUsers.push(user);
}
// Good: Explaining why (not obvious)
// Cache active users to avoid repeated database queries
const activeUsers = users.filter(user => user.active);
Comment when:
Don't comment when:
// Set name to Alice
const name = 'Alice';
// Check if user is active
if (user.active) {
// Log message
console.log('User is active');
}
These comments add no value. You can delete them.
// Use setTimeout to avoid blocking the UI thread during large file processing
setTimeout(() => processLargeFile(data), 0);
// Round to 2 decimals to match accounting requirements
const total = Math.round(price * 100) / 100;
// API returns timestamps in seconds, but JavaScript uses milliseconds
const date = new Date(timestamp * 1000);
These explain decisions that aren't obvious from the code alone.
For functions that others will use, document the interface:
/**
* Calculates the discounted price based on user tier
*
* @param {number} price - Original price in euros
* @param {string} userTier - User membership level ('basic', 'premium', 'vip')
* @returns {number} Final price after discount
*/
function calculateDiscount(price, userTier) {
const discounts = { basic: 0, premium: 0.1, vip: 0.2 };
return price * (1 - discounts[userTier]);
}
/**
* Brief description of what the function does
*
* @param {type} paramName - What this parameter represents
* @param {type} paramName2 - What this parameter represents
* @returns {type} What the function returns
*/
JSDoc is a documentation standard that tools can parse to generate documentation and provide better autocomplete.
/**
* Creates a new user account
*
* @param {string} username - Unique username (3-20 characters)
* @param {string} email - Valid email address
* @param {number} age - User age (must be 18+)
* @returns {Object} User object with id, username, email, and createdAt
* @throws {Error} If username is already taken
*/
function createUser(username, email, age) {
if (existingUsers.includes(username)) {
throw new Error('Username already exists');
}
return {
id: generateId(),
username,
email,
createdAt: new Date()
};
}
VS Code and other editors use JSDoc to show helpful tooltips when you hover over functions.
Common JSDoc tags:
@param {type} name - Description - Function parameters@returns {type} Description - Return value@throws {ErrorType} Description - Errors that might be thrown@example - Usage examples<aside> 💡
The best documentation is code that doesn't need documentation. Invest time in clear names and simple logic before reaching for comments.
</aside>
// WORKAROUND: API sometimes returns null instead of empty array
// Remove this once backend issue #247 is fixed
const items = response.data || [];
// NOTE: Must use var here due to hoisting requirements in legacy code
// TODO: Refactor to let once module system is updated
var globalConfig = loadConfig();
// HACK: Waiting 100ms for DOM to update
// Better solution needed - investigate MutationObserver
setTimeout(() => updateUI(), 100);
Use keywords like WORKAROUND, HACK, TODO, FIXME, NOTE to flag temporary solutions or future improvements.
Sometimes complexity is unavoidable. In these cases, explain the approach:
/**
* Implements the Collatz conjecture sequence
* See: <https://en.wikipedia.org/wiki/Collatz_conjecture>
*
* For any positive integer n:
* - If n is even: divide by 2
* - If n is odd: multiply by 3 and add 1
* - Repeat until reaching 1
*/
function collatz(n) {
const sequence = [n];
while (n !== 1) {
n = n % 2 === 0 ? n / 2 : 3 * n + 1;
sequence.push(n);
}
return sequence;
}
Good commenting principles:
Before commenting, ask:
Reading: