Never Use Semicolons

This post isn’t intended to reopen the age-old JavaScript debate, but merely to serve as a reference when people ask why JavaScript Standard Style enforces a “never use semicolons” rule.

The idea that you can “always use semicolons” and not worry about Automatic Semicolon Insertion (ASI) is completely incorrect.

All JavaScript developers absolutely must understand ASI, even those who “always use semicolons”. Take this example:

function foo () {
  return
    {
      bar: 1,
      baz: 2
    };
}

Woops, you remembered to put a semicolon, but doesn’t matter. ASI kicked in and changed your code to:

function foo () {
  return; // <– ASI adds a semicolon here. You now have a bug!
    {
      bar: 1,
      baz: 2
    };
}

So, it’s misleading to tell people that if they just “always use semicolons” their code is safe from surprising ASI behavior.

ASI will be with us forever. It’s about time you learned how it works. Not to worry: ASI is fully-specified in the ECMAScript language standard and all browsers implement it exactly the same way.

At the very least, consider using a linter that checks for unexpected ASI behavior. ESLint has a rule called no-unexpected-multiline which catches unexpected ASI behavior. And once you’re using a linter, it doesn’t matter whether you use or omit semicolons since the linter keeps you safe.

The argument for “never use semicolons”

It’s not actually that simple to “always use semicolons”. There are actually many edge cases where you still aren’t supposed to use a semicolon! For example:

function foo () {
  return 42; // ok
};           // <– AVOID!

var foo = function () {
}; // ok

And what about these cases:

class Foo {
  constructor () {
    if (baz) {
      return 42; // ok
    };           // <– AVOID!
    return 12;   // ok
  };             // <– AVOID!
};               // <– AVOID!

There are actually many more “edge cases” to keep in mind with “always use semicolons” than with “never use semicolons”.

If you “never use semicolons”, there’s only one rule: Never start a line with [, (, or `

In those cases, you simply prepend a ; like this:

;[1, 2, 3].forEach(bar)

However, if you frequently write code like this, you may be trying to be needlessly clever. This is actually much simpler:

const nums = [1, 2, 3]
nums.forEach(bar)

And if you use a linter like standard, then you don’t need to remember anything as unexpected ASI is reported as an error.

*The full list also includes some additional characters which would never actually appear at the start of an expression in real-world code: +, *, /, -, ,, .

Further reading

(If you liked this, you might like Cheating in Video Games.)

Thanks for reading! RSS Feed Icon

Feross Aboukhadijeh I'm Feross, a programmer, entrepreneur, open sorcerer, and mad scientist.

I build WebTorrent, a torrent library for the web, WebTorrent Desktop, the best desktop torrent app, and Standard, a JavaScript linter. In my free time, I build Play, a music video app and NodeFoo, a Node.js documentation site.

I also maintain 100+ packages on npm. All my code is freely accessible on my GitHub page. If you like my work, support me on Patreon. Thanks to all my awesome supporters!

Lastly, I run Study Notes, a site to help students study better and get into college, and have done that since I was in high school myself.

If you enjoyed this article, you should follow me on Twitter or sign up to get an email whenever I write something new:

Share this article with your friends: