Comments
Comments are notes for humans that the JavaScript engine ignores. Used well, they explain why code exists; used badly, they restate the obvious or — worse — go stale and lie to the reader. This page covers the mechanics of writing comments and the soft skill of knowing when not to.
Single-line comments
Anything after // on a line is a comment.
// Stores the user's current session token. Cleared on logout. let token = null; const price = 19.99; // pre-tax, in USD
Single-line comments are perfect for short clarifications and inline notes. Most modern code uses them for almost everything.
Multi-line comments
Anything between /* and */ is ignored, even if it spans many lines.
/*
The pricing engine assumes:
- amounts are integers in cents
- tax is applied AFTER discounts
- rounding follows banker's rounding
*/
function priceWithTax(cents, taxRate) {
// ...
}JSDoc — comments with structure
A multi-line comment that starts with /** (note the two stars) is a JSDoc block. Editors like VS Code parse JSDoc and use it for tooltips, parameter hints, and type inference — even without TypeScript.
/**
* Convert a price in cents to a localised display string.
*
* @param {number} cents - integer amount, e.g. 1999 for $19.99
* @param {string} [locale="en-US"] - BCP-47 locale tag
* @returns {string} formatted price, e.g. "$19.99"
*
* @example
* formatPrice(1999); // "$19.99"
* formatPrice(1999, "de-DE"); // "19,99 $"
*/
function formatPrice(cents, locale = "en-US") {
return new Intl.NumberFormat(locale, {
style: "currency",
currency: "USD",
}).format(cents / 100);
}Hovering formatPrice in your editor now shows the description, the parameter list and the example. The most-used tags are @param, @returns, @throws, @example, @deprecated and @see.
When to comment, and when not
The hard rule of thumb: comment why, not what.
Useless comments — the code already says this
// increment counter
counter++;
// loop through items
for (const item of items) {
// ...
}Useful comments — they say something the code can't
// Skip the first row — it's the header from the CSV import.
for (let i = 1; i < rows.length; i++) {
// ...
}
// HACK: Safari < 16 silently caches POSTs with JSON bodies.
// Adding a random query param forces a fresh request.
const url = endpoint + "?_=" + Date.now();Good comments tend to fall into a few buckets:
Intent — why the code exists, when good names already describe what it does.
Surprises — anything that looks wrong but is right (workarounds, browser bugs, business-rule oddities).
Trade-offs — "we picked this slower path because X".
External references — links to specs, tickets, RFCs or the article you cribbed an algorithm from.
Warnings — "do not call this from a render path", "this mutates the input on purpose".
Commented-out code
Tempting, almost always wrong. Commented-out blocks rot quickly — they reference variables that have been renamed, behaviour that has changed, and nobody dares delete them because "maybe it's important".
// const result = oldCalc(input); // TODO: switch back if v2 breaks
// console.log("debug:", result);
const result = newCalc(input);TODOs, FIXMEs and tags
Many teams agree on tag prefixes so IDEs and CI can find them:
// TODO: support locales beyond en-US (ticket PROD-1421) // FIXME: race condition when two tabs save at once // HACK: works around Chrome bug crbug.com/12345 // NOTE: this matches the legacy column order in v1 of the API
Comments and minifiers
In production builds, minifiers strip comments to shrink the file. The exception is comments that begin with /*! — minifiers preserve those, so they are conventional for license headers.
/*! my-lib v1.4.2 | MIT License | https://example.com/my-lib */
A small house style
Use
//for almost everything. Reserve/** ... */for JSDoc on exported functions and public APIs.Write full sentences with a capital letter and a period — comments are prose, not stickers.
Update or delete comments when you change code. A wrong comment is worse than no comment.
Don't comment to apologise (
// hack, sorry). Either fix it, or explain why it has to be this way.