JavaScript Comments

6 minute read

Comments are notes you leave in your code for humans — your teammates, your future self, or the maintainer six months from now who has no idea what the original author meant. The JavaScript engine completely ignores them. Used well, they clarify intent; used badly, they become outdated lies that mislead readers.

The Two Syntaxes

JavaScript has exactly two comment styles:

// Single-line comment — from // to end of line

/* Multi-line comment —
   can span as many lines
   as you need */
Style When to Use
// … Quick notes, end-of-line annotations, most everyday comments
/* … */ Multi-line explanations, license headers, temporarily disabling blocks

Single-Line Comments

Everything after // to the end of the line is ignored.

// Calculate the tax owed at the current bracket
const tax = income * 0.22;

const tax = income * 0.22;   // assumes 22% bracket — update yearly

You can comment out a single line of code while debugging:

// console.log("debug:", user);   // temporarily silenced
runJob(user);

Multi-Line Comments

/* … */ is useful for paragraphs of explanation or for disabling a chunk of code:

/*
  Pricing rules:
    - Base price = unit cost * quantity
    - Discount of 10% if quantity >= 100
    - Discount of 15% if customer is on the "gold" tier
*/
function priceFor(unit, qty, tier) {
  let total = unit * qty;
  if (qty >= 100) total *= 0.9;
  if (tier === "gold") total *= 0.85;
  return total;
}
/* Disable the legacy retry path until we redesign it
function legacyRetry(fn) {
  ...
}
*/

Warning: Multi-line comments don’t nest. /* outer /* inner */ outer */ ends at the first */ and leaves the rest as syntax garbage. Use // per line if you need to comment out code that already contains /* */.

JSDoc — Structured Doc Comments

JSDoc is a convention that turns /** … */ comments into machine-readable documentation. Editors like VS Code parse JSDoc to give you intellisense, type hints, and hover docs — even in plain JavaScript.

/**
 * Calculates the total price for an order.
 *
 * @param {number} unit  Per-unit cost in dollars
 * @param {number} qty   Quantity ordered
 * @param {"bronze"|"silver"|"gold"} tier  Customer loyalty tier
 * @returns {number} Total price after discounts
 */
function priceFor(unit, qty, tier) {
  // ...
}

Common JSDoc tags:

Tag Purpose
@param Document a function parameter
@returns Document the return value
@throws Errors the function can throw
@example A usage example
@deprecated Mark API as deprecated
@see Cross-reference to related code
@todo Pending work
@type Annotate a variable’s type
/** @type {Map<string, number>} */
const counts = new Map();

/**
 * @deprecated Use {@link fetchUser} instead.
 */
function getUser(id) { /* ... */ }

Tip: Even without TypeScript, JSDoc gives you ~80% of the editor support. It’s the cheapest way to make your codebase self-documenting.

When NOT to Comment

The best code is self-documenting — clear names, small functions, sensible structure. A comment that just restates the code is noise.

// ❌ Useless — the code already says this
// Increment counter by 1
counter = counter + 1;

// ❌ Noise — the function name is the comment
// Get the user's name
function getUserName() { return user.name; }

// ❌ Lies waiting to happen — code drifts, comment doesn't
// Loops 5 times
for (let i = 0; i < 10; i++) { ... }   // someone changed 5 → 10

Comment the WHY, Not the WHAT

The code shows the what. The comment should explain the why.

// ✅ Explains a non-obvious decision
// Use a 250ms debounce — anything faster causes the API to throttle us
const search = debounce(fetchResults, 250);

// ✅ Explains a workaround
// Safari 14 returns NaN here instead of throwing; coerce to 0
const value = parseFloat(raw) || 0;

// ✅ Explains business logic
// Free trial extended to 30 days for users who signed up before 2026-01-01
if (signupDate < new Date("2026-01-01")) trialDays = 30;

TODO / FIXME / NOTE Conventions

Most teams adopt three tag prefixes that IDEs highlight:

Tag Meaning
// TODO: Future work — not blocking
// FIXME: Known bug — needs fixing
// HACK: Intentional ugly workaround
// NOTE: Important context worth flagging
// XXX: Danger / “here be dragons”
// TODO: support multi-currency once the FX service ships
// FIXME: race condition when two saves overlap (CXPL-1234)
// HACK: workaround for Safari 14 IndexedDB bug
// NOTE: this order matters — auth must run before logging

Commenting Out Code While Debugging

Both styles work, with trade-offs:

// Approach 1: line-by-line with //
// console.log("a");
// console.log("b");
// console.log("c");

// Approach 2: block with /* ... */
/*
console.log("a");
console.log("b");
console.log("c");
*/

Tip: Most editors have a “toggle line comment” shortcut (Cmd+/ on Mac, Ctrl+/ on Windows). It uses // and handles selections cleanly. Use it.

Comments in HTML vs JavaScript

A subtle gotcha when JavaScript is embedded in HTML:

<!-- This is an HTML comment -->
<script>
  // This is a JavaScript single-line comment
  /* This is a JavaScript multi-line comment */

  <!-- ❌ This is NOT a JavaScript comment! -->
</script>
Where Single-line Multi-line
HTML — <!-- ... -->
CSS — /* ... */
JavaScript // /* ... */

License Headers

Many projects put a license block at the top of source files:

/*!
 * MyLibrary v2.4.1
 * Copyright (c) 2026 Example Corp.
 * Released under the MIT License.
 */

The leading /*! is a convention: most minifiers preserve comments that start with /*! so the legal notice survives the build.

Real-World Example

Here’s what well-commented production code looks like:

/**
 * Polls an endpoint until it returns a non-202 status,
 * with exponential backoff capped at 30s between attempts.
 *
 * @param {string} url      URL to poll
 * @param {object} options
 * @param {number} options.maxAttempts  Default 10
 * @returns {Promise<Response>}
 */
async function pollUntilDone(url, { maxAttempts = 10 } = {}) {
  let delay = 500;
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const res = await fetch(url);

    // 202 means "still processing" — keep waiting
    if (res.status !== 202) return res;

    await new Promise(r => setTimeout(r, delay));

    // Exponential backoff, but capped so we don't wait forever
    delay = Math.min(delay * 2, 30_000);
  }

  // TODO: surface a structured "TimeoutError" instead of throwing a string
  throw new Error(`Polling timed out after ${maxAttempts} attempts`);
}

Every comment earns its place: the JSDoc enables editor tooltips, the inline // 202 means… explains a magic number, the // Exponential backoff… clarifies intent, and the // TODO is honest about a known gap.

Best Practices Checklist

  • ✅ Use // for everyday inline comments
  • ✅ Use /** … */ JSDoc for public functions and exported APIs
  • ✅ Explain why, not what — let code show the what
  • ✅ Use TODO: / FIXME: consistently so they’re greppable
  • ✅ Update comments when you change the code they describe
  • ❌ Don’t restate the obvious
  • ❌ Don’t leave commented-out code in committed files — git remembers
  • ❌ Don’t write comments that lie (an outdated comment is worse than no comment)

What’s Next?

Comments document your code, but the real building blocks of a program are variables. Next we’ll see how to declare them with var, let, and const, and why two of those should never be used.

← Previous: JS Syntax Next: JS Variables →

Updated: