JavaScript Comments: How to Write Comments in JavaScript

JavaScript Comments: How to Write Comments in JavaScript

A JavaScript comment is invisible to the browser, ignored by the engine, and completely irrelevant to how the program runs. And yet a file without them becomes very hard to work with after a few hundred lines — especially when the developer reading it is you, six months later.

Unlike CSS, JavaScript has two comment syntaxes, plus a third documentation form that editors and tooling actually read. The rules are simple, but a handful of details trip people up: block comments cannot nest, a stray close delimiter turns the rest of the file into code, and a minifier will strip every comment you wrote unless you mark it as important.

This guide covers all of it: both syntaxes, JSDoc, where comments can appear, the nesting trap, comment markers, when not to comment, and how comments are handled in production. Every example runs live.

In one sentence: JavaScript has two comment syntaxes — a line comment that starts with // and runs to the end of the line, and a block comment that starts with /* and ends with */ — plus a JSDoc form that editors and documentation tools read.

What Is a JavaScript Comment?

A comment is text in a source file that the JavaScript engine discards before running anything. It is not executed, does not affect behavior, and does not appear on the page. It exists only for people who read the code.

That last part matters more than it sounds. Comments in a .js file are visible to anyone who opens the file in a browser — either by viewing the source or by opening DevTools. There is no such thing as a private comment in client-side JavaScript.

Comments are public

Anything you write in a JavaScript comment ships to every visitor’s browser. Never put credentials, API keys, internal URLs, customer data, or anything you would not want on a public billboard. This is a genuine security rule, not a stylistic preference.

What comments are for

📝

Explaining the why

Why a value was chosen, why a workaround exists, why a non-obvious approach was taken.

📑

Documenting an API

Function parameters, return values, and examples — in a form tools can read.

🔧

Disabling code temporarily

Commenting out a line while debugging, without deleting it and losing track.

🏷️

Marking outstanding work

TODO, FIXME, and similar markers that are easy to search for.

The Two Comment Syntaxes

JavaScript has two ways to write a comment. Both are universally supported and both are discarded by the engine. The only difference is how far they extend.

Line comment // to end of line

Runs from the two forward slashes to the end of the current line.

Anything on the next line is code again, so it is ideal for short notes.

Block comment /* … */

Spans from the opening slash-asterisk to the matching asterisk-slash.

Can cover any number of lines — used for longer explanations or disabling code.

// A line comment. The engine ignores everything after the slashes.

const price = 19.99;   // a trailing comment after a statement

/* A block comment can span
   several lines and is often
   used for a longer explanation. */

const tax = 0.2;

/* Block comments also work inline */ const total = price * (1 + tax);

/*
 * The block form is often styled
 * with a leading asterisk on each
 * line. The asterisks are decoration —
 * the engine does not care.
 */

The leading asterisk on each line of a block comment is purely a convention. It makes a long comment easy to scan and keeps it visually separated from the code. The engine ignores it completely.

Which one to use

Choosing between line and block comments
Situation Use
A short note about one line // — the line comment
A trailing note after a statement // — the line comment
A multi-line explanation /* ... */ — the block comment
Temporarily disabling a block of code /* ... */ — the block comment
Documenting a function for tools /** ... */ — JSDoc, covered next
Disabling a single line of code // — the line comment
Prefer line comments

Line comments cannot cause the nesting problem covered later, they are easier to edit, and a stray one is harmless. Reach for a block comment only when you genuinely need to span multiple lines or disable a block.

The Third Form: JSDoc Comments

A comment that starts with /** — a slash followed by two asterisks — is a JSDoc comment. To the JavaScript engine it is an ordinary block comment. To your editor and to documentation tools, it is structured metadata.

/**
 * Calculate the total price of an order, including tax.
 *
 * @param {number} subtotal - The pre-tax amount in dollars.
 * @param {number} [taxRate=0.2] - The tax rate as a decimal. Defaults to 0.2.
 * @returns {number} The total amount, including tax.
 * @throws {TypeError} If subtotal is not a number.
 *
 * @example
 * calculateTotal(100);       // 120
 * calculateTotal(100, 0.1);  // 110
 */
function calculateTotal(subtotal, taxRate = 0.2) {
    if (typeof subtotal !== 'number') {
        throw new TypeError('subtotal must be a number');
    }
    return subtotal * (1 + taxRate);
}

The tags are the whole point. Your editor reads them to show a tooltip when you hover over calculateTotal, to autocomplete the parameter names as you type, and to warn you if you pass the wrong type. Documentation generators read them to build an API reference without any extra effort.

The tags you will use most

@param

Describes a parameter. Include the type in braces and a description after a dash.

@returns

Describes what the function returns, including its type.

@throws

Documents an exception the function may throw and under what conditions.

@example

Shows a working usage example. The most valuable tag for the next reader.

@typedef

Defines a custom type that other annotations can reference by name.

@deprecated

Marks something as obsolete. Editors will strike it through when used.

@since

Records which version introduced the feature. Useful in libraries.

@see

Points to a related function, class, or external documentation.

Optional and default parameters

/**
 * Create a user record.
 *
 * @param {Object} data - The user data.
 * @param {string} data.name - The user's full name. Required.
 * @param {string} [data.email] - The user's email. Optional.
 * @param {string} [data.role='viewer'] - The user's role. Defaults to 'viewer'.
 * @returns {{id: number, name: string, role: string}}
 */
function createUser({ name, email, role = 'viewer' }) {
    return { id: nextId(), name, role };
}

Square brackets around a parameter name mark it as optional. Writing [name=default] records both that it is optional and what the default is.

JSDoc is optional but valuable

Nothing enforces JSDoc. Your code runs fine without it. But on a function that other people will call — especially in a library or a shared internal module — a single well-written JSDoc block saves every future reader a trip into the implementation.

Where Comments Can Go

Unlike CSS, JavaScript comments can appear almost anywhere the parser expects a token, because the engine strips them before parsing. There are five places you will actually use.

// 1. At the top of the file — a file-level header
//    describing what this module does.

/* 2. As a section separator, dividing a long file
   ------------------------------------------------------------------ */

const API_URL = 'https://api.example.com';

// 3. Above a function, explaining what it does
function fetchUser(id) {
    // 4. Inside the function body
    const url = `${API_URL}/users/${id}`;
    return fetch(url).then(r => r.json());
}

const timeout = 5000; // 5. After a statement, on the same line

/* 6. Between statements, to introduce what comes next */

const config = {
    retries: 3,       // 7. Inside an object literal
    timeout: 5000
};

const list = [
    'a',   // 8. Inside an array literal
    'b'
];

There is one place a comment cannot go: inside a token. You cannot split an identifier, a string, or a number in half with a comment and expect the two halves to rejoin.

Incorrect — splits a token
const user/* name */Name = 'Ada'; // The parser sees two identifiers: // `user` and `Name` — which is a // syntax error. const x = 1/* five */0; // Also an error.
Correct — comment between tokens
const userName = 'Ada'; /* the name */ const x = 10; /* value */ // The comment sits between two // complete tokens, so the parser // is not confused.

The Nesting Trap

Block comments cannot be nested. A block comment ends at the first */ it finds, no matter how many /* opened before it. This is the single most damaging comment mistake in JavaScript, because it turns an entire block of intended-to-be-ignored code into live code.

/* Outer comment begins /* Inner comment */ This text is no longer commented out */
1
The outer comment opens The engine starts discarding tokens, waiting for a matching */.
/* Inner comment */
2
The first close ends the comment The inner */ closes the outer comment. The outer one never gets its own closing delimiter.
This text is no longer commented out
!
Now parsed as code The remaining text is live JavaScript. If it is not valid, the script throws a SyntaxError and nothing runs at all.

How this happens in real life

You have a function with a block comment inside it. You decide to comment out the whole function while debugging.

Incorrect — the inner close ends it early
/* function save(data) { /* validate first */ if (!data) return; persist(data); } */ console.log('after'); // This line is fine — but everything // between the inner close and here // was parsed as code, and most of it // is not valid JavaScript.
SyntaxError: Invalid or unexpected token The parser chokes on the text that was meant to be ignored.

The outer comment closes at /* validate first */. Everything after that — including the closing brace and the final */ — is parsed as live code, which is almost always invalid.

The fix: convert inner block comments to line comments

Line comments do not end a block comment. That is the entire reason they are the safer choice.

Incorrect — inner block comment
/* function save(data) { /* validate first */ if (!data) return; persist(data); } */
Correct — inner line comment
/* function save(data) { // validate first if (!data) return; persist(data); } */ // The // inside does not close // the outer block comment.
Before commenting out a block, check for */

Scan the block for any existing */. If there is one, convert the inner comment to a // line comment first. This single habit saves a very confusing debugging session.

When you need a comment inside a comment

There is no way to nest block comments, but two patterns achieve the same thing. The first replaces the inner delimiters with a visual marker that looks similar but closes nothing:

/* Outer comment begins
   |  Inner note — a pipe stands in for the asterisk,
   |  so this text does not close the outer comment.
   Outer comment ends here */

The second splits the note into two separate comments, one above the other, so neither sits inside the other:

/* A note about the code that follows */

/* A second note, kept separate so neither nests */
DevTools is usually faster

If you are commenting out code just to see what happens, the Sources panel in DevTools lets you set a breakpoint and step over a line without editing the file at all. No risk of a stray */, no chance of forgetting to undo it.

Comments for Documentation

This is where comments earn their place. A well-commented file is dramatically easier to return to after six months, and dramatically easier for someone else to work in.

File headers

/**
 * @file Shopping cart utilities.
 *
 * Handles line items, totals, and currency conversion.
 * All amounts are in cents to avoid floating-point errors.
 */

const CURRENCY = 'USD';

// ... rest of the file

A file header tells the next reader what this module is for before they have read a single line of implementation. The @file tag is a convention that documentation generators recognize.

Section separators

// ============================================================
//  Configuration
// ============================================================

const API_URL = 'https://api.example.com';
const TIMEOUT = 5000;

// ============================================================
//  Data loading
// ============================================================

async function loadUser(id) { /* ... */ }

// ============================================================
//  Rendering
// ============================================================

function renderUser(user) { /* ... */ }

A row of equals signs is a widely used convention for marking sections in a long file. It is not required by the language, but it makes the file scannable at a glance.

Explaining the why, not the what

Useless — restates the code
// Set the timeout to 5000 const timeout = 5000; // Increment i i++; // Check if user exists if (user) { /* ... */ }
Useful — explains a decision
// 5s matches the load balancer's idle timeout — // anything longer gets cut off at the proxy. const timeout = 5000; // The retry counter is reset here rather than // on success, so a failed retry does not loop. attempts = 0;

Noting workarounds

Browser quirks and workarounds are exactly the kind of thing that makes no sense six months later without an explanation. Comments matter most here.

function focusInput() {
    const input = document.getElementById('search');

    // requestAnimationFrame is required here: calling focus()
    // immediately after making the element visible fails in
    // Safari because the layout has not flushed yet.
    requestAnimationFrame(() => input.focus());
}

// translateZ(0) forces GPU compositing, which fixes a flicker
// on scroll in older Chromium builds.
element.style.transform = 'translateZ(0)';

Comment Markers and Conventions

A handful of keywords are conventional enough that every developer recognizes them. Because they are searchable, they surface outstanding work across an entire codebase in seconds.

  • Something to do later. A known gap that is not urgent enough to fix now. Searchable, so it does not get forgotten.
  • Something that is broken. A known bug or a fragile piece of code that needs attention. More urgent than a TODO.
  • An explanation for the next reader. Context that is not obvious from reading the code.
  • A deliberate workaround. Something that looks wrong but is correct, and should be revisited when the underlying cause goes away.
  • Questionable or dangerous code. A warning flag that this section deserves scrutiny.
// TODO: replace this hard-coded list with an API call
const categories = ['books', 'games', 'music'];

// FIXME: this breaks when the name contains an apostrophe
const escaped = name.replace(/'/g, '');

// NOTE: the API returns dates in UTC, so we convert to local time here
const localDate = new Date(data.timestamp + 'Z');

// HACK: Safari fires this event twice; the flag prevents double handling
let handled = false;
element.addEventListener('click', () => {
    if (handled) return;
    handled = true;
    doSomething();
});

// XXX: this loop is O(n²) and will not scale past a few hundred items
for (const a of list) { for (const b of list) { /* ... */ } }
Search your markers

A quick grep for TODO or FIXME in a codebase surfaces every outstanding item in seconds. Many editors have built-in panels that list them across the whole project.

When NOT to Comment

Comments cost maintenance, and a stale comment is worse than no comment — it actively misleads. These are the cases where a comment makes the code worse, not better.

1. Commenting the obvious

Noise
// Declare i and set it to 0 let i = 0; // Loop while i is less than 10 while (i < 10) { // Increment i i++; } // Log the result console.log(i);
Signal
// Process in batches of 10 to stay under // the API rate limit of 12 requests/second let i = 0; while (i < 10) { i++; } console.log(i);

2. Commenting out code and leaving it there

Dead weight
function total(items) { return items.reduce((s, i) => s + i.price, 0); // return items.length; // return items[0]; // return items.map(i => i.price).join(); // TODO: ask which one is right }
Clean
function total(items) { return items.reduce((s, i) => s + i.price, 0); } // Version control remembers what was // there before. There is no reason to // keep it in the file.

3. Leaving a comment where a rename would do

A comment patching a bad name
// d = days since last login const d = Date.now() - user.lastLogin; // btn = the save button const btn = document.getElementById('save');
The name says it
const daysSinceLogin = Date.now() - user.lastLogin; const saveButton = document.getElementById('save');

4. Writing a comment instead of fixing the code

The comment admits the problem
// this is a mess but it works function f(a, b, c, d, e) { if (a) { if (b) { if (c) { return d + e; } } } return 0; }
Fix it, then no comment is needed
function calculateTotal(a, b, c, d, e) { if (!a || !b || !c) return 0; return d + e; }

5. Commenting through a stale reference

A comment that describes an old version of the code is worse than nothing. When you change a function, check the comment above it. A comment that no longer matches its code is a bug waiting to happen.

A comment is a promise

It promises that the text describes the code below it. When the code changes and the comment does not, that promise is broken, and the next reader trusts something that is no longer true. When you edit a function, edit its comment.

Comments and Minification

In development, comments cost nothing but a few bytes. In production, they are removed entirely by a minifier — the same tool that shortens variable names and strips whitespace.

What a minifier does

Source
// Calculate the discounted price function getDiscount(price, rate) { /* The rate is a decimal, so 0.2 means 20% off */ return price * (1 - rate); }
After minification
function getDiscount(n,e){return n*(1-e)}

Every comment is gone, every variable is renamed, every unnecessary character is removed. The behavior is identical; the file is a fraction of the size.

The bang comment

Most minifiers preserve a comment that starts with an exclamation mark right after the opening delimiter. This is how license headers survive a build:

/*! My Library v2.0 | MIT License | example.com/license */

// This comment will be stripped by the minifier

/*! This one will be kept */

The convention is sometimes called an important comment or a bang comment. It exists so that legally required notices are not removed by a build step.

Source maps

Once the code is minified, DevTools would show you line 1 of a file with no readable names. A source map fixes that — it is a separate file that tells the browser where each piece of minified code came from.

// A source-map comment at the end of a minified file
//# sourceMappingURL=app.min.js.map

This comment uses a special form — //# — that tools recognize. It is generated by the build step, not written by hand. With it, the DevTools Sources panel shows you the original file, with its original names and its original comments.

Write comments freely

There is no reason to hold back on comments for performance. The build step will remove them, and a source map will bring them back in DevTools. The only cost is the bytes in your source file, which nobody downloads.

Common Comment Mistakes

Each of these breaks something — either silently or with an error that points to the wrong place. They are the ones that come up most often.

1. Nesting block comments

Incorrect — ends at the first */
/* outer /* inner */ this text is now live code */
SyntaxError The inner */ closes the comment, and the remaining text is parsed as JavaScript.

2. Forgetting the closing delimiter

Incorrect — swallows the rest of the file
/* Section header const a = 1; const b = 2; // Missing the closing */ console.log(a);
Nothing after the opening runs Every line below the comment is discarded, because the parser never finds the closing delimiter.

3. A stray closing delimiter

Incorrect — orphaned */
const a = 1; */ const b = 2;
SyntaxError: Unexpected token ‘*’ A close delimiter with no matching open is a syntax error. This happens when a half-finished edit leaves one behind.

4. Using an HTML comment inside a script

Incorrect — not a JavaScript comment
<script> <!-- this is not a JavaScript comment --> const a = 1; </script>
SyntaxError HTML comment syntax means nothing inside a script block. Use // or /* */.

5. Commenting out a line that contains a line-break-sensitive statement

Incorrect — breaks a return statement
function getValue() { return // returns undefined! 42; } // The newline after `return` ends // the statement. The 42 is unreachable.
Correct — keep it on one line
function getValue() { return 42; } // Or, if you want a comment, put it // above the return, not between the // keyword and the value.

6. A comment that contradicts the code

Incorrect — the comment is stale
// Returns the user's full name function getUser(id) { return { id, email }; } // The comment promised something // the function does not do. Worse // than no comment at all.
Correct — matches the code
// Returns the user's id and email only. // The full name requires a second API call. function getUser(id) { return { id, email }; }

7. Putting anything private in a comment

Incorrect — ships to every visitor
// TODO: remove the staging key // sk_test_51H8x... before launch const key = 'sk_test_51H8x...'; // This is visible to anyone who // opens DevTools.
Correct — no secrets in client code
// Loads the public key from a meta tag // that the server renders per request. const key = document .querySelector('meta[name="api-key"]') .content;

8. A missing space after //

Incorrect — hard to read
//calculate the total const total = sum(items); //increment counter count++;
Correct — a space after the slashes
// Calculate the total const total = sum(items); // Increment the counter count++;

One style of line comment does omit the space: a commented-out line of code. Keeping the original indentation and adding // at the column makes it visually obvious that the line is disabled code, not prose.

function save(data) {
    // validate(data);
    persist(data);
}

// The commented-out call keeps its
// original indentation, which makes
// it visually distinct from a note.
Read the first error, not the last

A single syntax error often produces a cascade of messages as the parser tries to recover. The first one is the real problem; the rest are consequences. Fix the first and reload.

Best Practices

These habits keep comments useful rather than noise as a codebase grows.

🎯

Comment the why, not the what

The code already says what it does. A comment should say why it does it that way.

//

Prefer line comments

They cannot trigger the nesting trap and are easier to edit safely.

📑

Use JSDoc on public functions

@param, @returns, and @example pay for themselves the moment someone else calls the function.

🔤

Use standard markers

TODO, FIXME, NOTE, and HACK are searchable and understood everywhere.

📦

Never nest block comments

Check for an inner */ before commenting out a block. Convert it to a line comment first.

🗑️

Delete dead code

Commented-out code belongs in version history, not in the file.

✂️

Keep them short

One or two lines is usually enough. Long essays go stale and get skipped.

⚖️

Use /*! for licenses

The bang form survives minification, so legal notices are not stripped.

🔒

Assume comments are public

Never put credentials, API keys, or private URLs in a comment.

The one-line summary

Prefer //, never nest block comments, use JSDoc for public APIs, explain the why rather than the what, and delete dead code instead of commenting it out.

Frequently Asked Questions

1. How do you write a comment in JavaScript?

JavaScript has two comment syntaxes. A line comment starts with // and runs to the end of the line. A block comment starts with /* and ends with */, and can span multiple lines. A third form starting with /** is a JSDoc comment that documentation tools read.

2. What is the difference between // and /* */ in JavaScript?

A double-slash comment runs only to the end of the line, so it is used for short notes. A slash-asterisk block comment can span any number of lines and is used for longer explanations or for temporarily disabling a block of code.

3. Can JavaScript comments be nested?

Block comments cannot be nested. A block comment ends at the first */ it encounters, so putting a comment inside a comment closes the outer one early and turns the rest of the text into live code. Line comments using // can appear inside a block comment without ending it.

4. Do JavaScript comments affect the page?

No. Comments are discarded by the JavaScript engine before the code runs, so they have no effect on behavior, performance, or rendering. They are visible only to someone reading the source.

5. What is a JSDoc comment?

A JSDoc comment starts with /** and uses tags such as @param, @returns, and @example. Editors and documentation generators read these to provide autocomplete, type hints, and generated API documentation. They are ordinary block comments as far as the engine is concerned.

6. Are JavaScript comments removed in production?

Yes. A minifier strips comments to reduce file size. A comment that starts with an exclamation mark, such as a license header, is preserved by most minifiers because it is marked as important.

7. Do comments in JavaScript affect SEO?

No. Search engines do not read JavaScript comments as content and they are not a ranking factor. Putting keywords in comments has no effect and is not a substitute for real content or metadata.

8. How do I comment out a block of code in JavaScript?

Wrap the block in /* and */. If the block already contains a block comment, the outer comment closes at the first */ inside it, so remove or convert any inner block comments first. Line comments using // do not cause this problem.

9. What is the difference between a JavaScript comment and an HTML comment?

HTML comments use <!-- and --> and are used in markup. JavaScript comments use forward slashes and are used inside a script element or a .js file. Putting an HTML comment inside a script block does not create a JavaScript comment.

10. Can I use HTML comments inside a script tag?

There is a legacy behaviour where <!-- acts as a line comment in some contexts, intended to hide scripts from very old browsers. It is obsolete and should not be used. Use // for line comments inside script blocks.

11. What are TODO and FIXME comments?

They are conventional markers. TODO marks something to do later, FIXME marks something broken that needs attention, NOTE explains context for the next reader, and HACK marks a deliberate workaround. Because they are searchable, they surface outstanding work across a codebase.

12. Should I comment every line of JavaScript?

No. Commenting every line adds noise and goes stale quickly. Comment the why rather than the what, and reserve comments for decisions that are not obvious from reading the code — a workaround, a constraint, a non-obvious choice of value.

Key Takeaways

  • JavaScript has two comment syntaxes: // for a line, /* */ for a block.
  • A third form, /** */, is a JSDoc comment that editors and tools read.
  • Block comments cannot be nested — the first */ closes the comment.
  • An unclosed block comment swallows the rest of the file.
  • Line comments inside a block comment do not end it, so they are the safer choice.
  • Comments have no effect on behavior, performance, or SEO.
  • Minifiers strip comments, except those written as /*! ... */.
  • Source maps bring comments back into DevTools after minification.
  • Comment the why, not the what.
  • Markers like TODO, FIXME, NOTE, and HACK are searchable across a codebase.
  • Delete commented-out code — version control already remembers it.
  • Never put anything private in a comment; it ships to every visitor.

What to Learn Next

Now that comments are clear, the next step is the language around them. Start with JavaScript Syntax Explained and What Is JavaScript?.

From there, explore JavaScript Functions Explained, JavaScript Objects, and JavaScript Array Methods. When you are ready to work with the page, read How to Add JavaScript to HTML and Working with the DOM.

If you are still connecting the pieces, read How JavaScript Works and CSS Comments for the surrounding context.

Practice Challenge

The fastest way to internalize the rules is to break them on purpose and watch what happens. This exercise takes about twenty minutes.

  1. Create index.html and app.js, and load the script with <script src="app.js" defer></script>.
  2. At the top of app.js, write a JSDoc-style file header describing what the file does. Use @file.
  3. Write a function that returns a value. Above it, add a JSDoc block with @param, @returns, and @example. Hover over the function name in your editor and confirm the tooltip appears.
  4. Add a // TODO, a // FIXME, and a // NOTE comment somewhere in the file. Confirm your editor lists them in its problem panel.
  5. Refresh the page and confirm that none of the comments appear in the rendered output.
  6. Now break it: wrap a function in a block comment that contains a second block comment inside it. Refresh and read the console error. Fix it by converting the inner comment to //.
  7. Break it again: delete a closing */ from a block comment. Refresh and confirm that every line below it stops running. Put it back.
  8. Add a stray */ on its own line. Refresh and read the syntax error.
  9. Put an HTML comment <!-- ... --> inside the script block. Refresh and read the syntax error.
  10. Now open DevTools, inspect the Sources panel, and confirm that all your comments are visible in the loaded app.js.
  11. Finally, run the file through a minifier (any online tool works). Compare the output and confirm that every comment is gone and every name is shortened.

If you complete those steps, you have written both comment syntaxes, watched JSDoc drive editor tooltips, produced four different syntax errors by hand, seen how a single stray delimiter breaks an entire file, and watched a minifier strip everything away. That sequence — write, break, read the error, fix — is how the syntax stops being something you look up and becomes something you know.

Inar Learn
Inar Learnhttps://inarlearn.com
Inar Learn is an innovative online learning platform offering high-quality courses, tutorials, and resources to help learners gain practical skills and grow their knowledge.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here