Single-Line Comments
A single-line comment starts with // and extends to the end of the line. Everything after // on that line is ignored by JavaScript.
// This is a standalone comment explaining the next line
const TAX_RATE = 0.08; // 8% sales tax β required by state law
// Calculate the final price including tax
function addTax(price) {
return price * (1 + TAX_RATE);
}
// Single-line comments are ideal for:
// - Brief explanations
// - Annotating specific values or magic numbers
// - Quick notes during development
The code already shows what is happening. Comments should explain why β the reason for a decision, a non-obvious constraint, a business rule, or a workaround for a known issue. // increment i above i++ is useless. // start at 1 to skip the header row is valuable.
Multi-Line Comments
Multi-line comments start with /* and end with */. Everything between these delimiters is a comment, regardless of how many lines it spans.
/*
This function validates a UK postcode format.
Valid examples: "SW1A 1AA", "EC2R 8AH", "W1A 0AX"
Note: This is a simplified regex β it does NOT guarantee
the postcode actually exists in Royal Mail's database.
Use a postcode lookup API for verified addresses.
*/
function isValidUKPostcode(postcode) {
const regex = /^[A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2}$/i;
return regex.test(postcode.trim());
}
/* Quick inline multi-line comment */
const MAX = /* the theoretical max before overflow */ 2147483647;
Commenting Out Code for Debugging
A common technique is temporarily commenting out code to isolate bugs or test alternatives. Most editors support Ctrl + / (or Cmd + /) to toggle line comments.
function processOrder(order) {
// validateOrder(order); // Temporarily disabled while debugging
const total = calculateTotal(order.items);
/*
// Old discount logic β keeping for reference
if (order.coupon) {
total = total * 0.9;
}
*/
// New discount logic
if (order.coupon && isValidCoupon(order.coupon)) {
return total * getCouponDiscount(order.coupon);
}
return total;
}
Commented-out code clutters your codebase, confuses other developers, and often represents dead code that should be deleted. If you need to keep old logic, use version control (git) β you can always retrieve deleted code from git history. Remove commented-out code before committing.
JSDoc Comments
JSDoc is a standardized comment format that documents functions, parameters, return values, and types. It uses /** */ (double asterisk) and special @ tags. IDEs like VS Code read JSDoc to provide intellisense, type hints, and hover documentation.
/**
* Calculates the area of a rectangle.
*
* @param {number} width - The width of the rectangle in pixels.
* @param {number} height - The height of the rectangle in pixels.
* @returns {number} The area in square pixels.
* @throws {Error} If width or height is negative.
*
* @example
* const area = rectangleArea(10, 5);
* console.log(area); // 50
*/
function rectangleArea(width, height) {
if (width < 0 || height < 0) {
throw new Error("Width and height must be non-negative.");
}
return width * height;
}
/**
* Represents a user in the system.
* @typedef {Object} User
* @property {string} id - Unique user identifier.
* @property {string} name - Display name.
* @property {string} email - Email address.
* @property {boolean} isAdmin - Whether the user has admin privileges.
*/
/**
* Fetches a user by their ID.
* @param {string} userId - The user's unique identifier.
* @returns {Promise<User|null>} The user object, or null if not found.
*/
async function getUserById(userId) {
// implementation...
}
| JSDoc Tag | Purpose | Example |
|---|---|---|
@param | Documents a parameter | @param {string} name - User's name |
@returns | Documents return value | @returns {number} The sum |
@throws | Documents thrown errors | @throws {TypeError} If invalid input |
@example | Usage example | @example myFn(1, 2) // 3 |
@typedef | Defines a custom type | @typedef {Object} Config |
@deprecated | Marks outdated API | @deprecated Use newFn() instead |
@see | Links to related docs | @see https://mdn.io/... |
Good vs Bad Comments
// β BAD COMMENTS β These explain WHAT the code does (already obvious)
// Declare a variable called count and set it to 0
let count = 0;
// Add 1 to count
count++;
// Return the user's name
return user.name;
// β
GOOD COMMENTS β These explain WHY (not obvious from code)
// Start counting from 0; the display will add 1 for 1-based numbering
let count = 0;
// Increment on each failed attempt; lockout triggers at MAX_ATTEMPTS
count++;
// Return the display name β falls back to email prefix if name isn't set
return user.name || user.email.split("@")[0];
// β
GOOD: Explain a non-obvious business rule
// Per GDPR Article 17, we must not log the user's IP address
const requestLog = { timestamp, endpoint }; // IP deliberately excluded
// β
GOOD: Explain a workaround
// Array.from() instead of spread operator due to IE11 transpilation bug (see #GH-412)
const items = Array.from(nodeList);
TODO and FIXME Comments
It's a universal convention to use TODO: and FIXME: prefixes in comments to mark work that needs to be done. Many IDEs and linters can find and list these automatically.
// TODO: Add input validation before this goes to production
function saveUser(data) {
db.insert(data);
}
// FIXME: This breaks when the user list is empty β returns undefined
function getFirstUser(users) {
return users[0].name;
}
// HACK: Temporary fix for the timezone offset bug β remove after Q3 backend update
const adjustedDate = new Date(timestamp - 3600000);
// NOTE: This algorithm is O(nΒ²) β acceptable for now with small datasets,
// but needs to be replaced with a hash map approach for scale
function findDuplicate(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j]) return arr[i];
}
}
}
ESLint Disable Comments
When ESLint flags a rule violation you intentionally need to break, you can disable the rule for a specific line. This is an escape hatch β use it sparingly and always explain why.
// Disable a rule for one line (add explanation!)
const result = eval(expression); // eslint-disable-line no-eval -- sandboxed input, validated upstream
// Disable for the next line
// eslint-disable-next-line no-console
console.log("Debug output:", data);
// Disable for a block
/* eslint-disable no-magic-numbers */
const RETRIES = 3;
const TIMEOUT = 5000;
const MAX_SIZE = 1048576;
/* eslint-enable no-magic-numbers */
// Disable for the entire file (rarely justified β use at the top)
/* eslint-disable no-unused-vars */
Use comments to group related code blocks in a file: // === UTILITY FUNCTIONS ===, // === API CALLS ===, // === EVENT HANDLERS ===. In larger codebases these sections should be split into separate files/modules, but section headers help readability in smaller files.
ποΈ Practical Exercise
- Write a function
calculateShipping(weight, distance)with a full JSDoc comment including@param,@returns,@example, and a description of the pricing formula. - Review a function you've written in a previous exercise and identify any comments that explain what the code does. Rewrite them to explain why instead.
- Add a
TODO:comment to a function that needs input validation, describing exactly what needs to be added. - Deliberately trigger an ESLint warning (if ESLint is set up), then use an inline disable comment with an explanation.
- Write a multi-line
/* */comment explaining a complex algorithm or business rule in a function of your choice.
π₯ Challenge Exercise
Take the following undocumented utility file and add proper JSDoc comments to every function. Include parameter types, return types, a brief description, and at least one @example per function. Also identify which comments already present are "bad" (explain what) and which are "good" (explain why):
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
function groupBy(arr, key) {
return arr.reduce((acc, item) => {
(acc[item[key]] = acc[item[key]] || []).push(item);
return acc;
}, {});
}
π Summary
- Single-line comments use
//; multi-line use/* */. - JSDoc comments use
/** */with@param,@returns,@throws,@exampletags for documenting functions. - Comment WHY, not WHAT β the code shows what happens; comments explain the reasoning.
- Use
TODO:,FIXME:,HACK:,NOTE:prefixes for actionable comments. - Don't commit commented-out code β use git history instead.
- ESLint disable comments are a last resort; always include an explanation of why.
Interview Questions
- What is the difference between single-line and multi-line comments in JavaScript?
- What is JSDoc and why is it useful?
- What makes a comment "good" vs "bad"?
- When would you use a TODO comment vs just fixing the problem?
- What is the
@paramJSDoc tag used for?
Frequently Asked Questions
In modern JavaScript, comments have effectively zero runtime performance impact. Build tools (like Webpack, Vite, or esbuild) automatically strip comments from production bundles. The only minor concern is file download size in unbuilt code, but minifiers handle this. Write as many comments as help maintainability β don't skip them for performance reasons.
Not necessarily. Simple, self-explanatory functions with clear names and descriptive parameter names often don't need JSDoc: function double(n) { return n * 2; } is clear enough. JSDoc adds the most value for: public APIs, complex algorithms, functions with non-obvious parameter expectations, functions that throw, and any code others will need to use without reading the implementation.
TypeScript is JavaScript with static type syntax built in. JSDoc's type annotations ({string}, {number}, {Promise<User>}) serve a similar purpose but through comments rather than syntax. VS Code actually uses JSDoc type comments to provide TypeScript-like type checking in plain JavaScript files when you add // @ts-check at the top. Many teams use JSDoc as a lighter alternative to TypeScript.
No. JavaScript doesn't support nested block comments. /* outer /* inner */ still outer */ β the comment ends at the first */, so still outer */ becomes invalid code. If you need to comment out a block that already contains multi-line comments, convert them to single-line comments first, or use your editor's "comment out" feature which handles this automatically.
Use the JSDoc tool (npm install -g jsdoc). Running jsdoc src/ generates an HTML documentation site from your JSDoc comments. Other popular alternatives are TypeDoc (for TypeScript), ESDoc, and documentation.js. These tools create professional API documentation sites automatically from your code comments.