Table of Contents
Semicolons and Automatic Semicolon Insertion are two of the most misunderstood topics in JavaScript. In this tutorial, you will learn about what ASI is. You will also learn about the rules that determine where semicolons are required. This will also help you understand when ASI can cause you troubles.
Introduction: Semicolons are … not required
When I started with JavaScript I’ve been told that semicolons are required. I was supposed to add semicolon at the end of each statement. I followed this rule for more than five years. Then, I came across a [JavaScript Standard Style], or standard.js for short. While reading this style guide I there was one rule that surprised me.
This rule was simple and straightforward: “No semicolons”. Wait, what? I thought that semicolons are required. How can this rule forbid using something that is required? As it turned out, semicolons in JavaScript are yet another confusing topics, just as this. In JavaScript, there is something called Automatic Semicolon Insertion, or ASI.
Automatic Semicolon Insertion made simple
First, what is this Automatic Semicolon Insertion? The ASI is one of JavaScript’s syntactic features. Without a doubt, it is probably one of JavaScript’s most controversial. Automatic Semicolon Insertion is something like a subprogram or process automatically running on a background when JavaScript parser parses your code.
What this subprogram, or process, does is it inserts semicolons where it is necessary when you run your code. In JavaScript, there are situations where semicolons are required. Otherwise, your code could break. The job of Automatic Semicolon Insertion is to make sure your code follows these rules. If some required semicolon is missing ASI will add it.
Rules of Automatic Semicolon Insertion
There are three main rules for Automatic Semicolon Insertion that state where semicolons are required, and will be inserted. These rules are, as specified in ECMAScript Language Specification, as following:
1) When the program contains a token that is not allowed by the formal grammar, then a semicolon is inserted if (a) there is a line terminator at that point, or (b) the unexpected token was a closing brace (}) or closing parenthesis ()).
2) When, as the source text is parsed from left to right, the end of the input stream of tokens is encountered and the parser is unable to parse the input token stream as a single instance of the goal nonterminal, then a semicolon is automatically inserted at the end of the input stream.
3) When a “restricted production” (return
, break
, continue
, throw
and ++
and --
postfix operators) is encountered and contains a line terminator in a place where the grammar contains the annotation, then a semicolon is inserted.
To make these rules easier to understand, we will break them down further to seven rules. I hope that this will also make them easier for you to remember and recall later. When you learn these rules you will know where missing semicolon can cause problems. Let’s take a look at each along with some examples of what can happen.
Rule no.1
The first rule is that ASI will add a semicolon when the next line starts with code that breaks the current one. This can happen when code spawns over multiple lines.
// EXAMPLE
const sum = 5 + 5
(sum).toFixed(3)
// Is interpreted as:
const sum = 5 + 5(sum).toFixed(3);
// ReferenceError: Cannot access 'sum' before initialization
// JavaScript parser basically assumes
// that what we want to do is a function call
// i.e.: 5(sum), calling function 5 with parameter sum
// FIX:
const sum = 5 + 5;
(sum).toFixed(3)
// Is interpreted as:
const sum = 5 + 5;
sum.toFixed(3);
// Or
// EXAMPLE
const mishmash = 13 + 'world'
[13].length
// TypeError: Cannot read property 'length' of undefined
// Is interpreted as:
const mishmash = 13 + 'world'[13].length;
// JavaScript parser basically assumes
// that we want to know the length of character on 12th index
// FIX:
const mishmash = 13 + 'world';
[13].length
// ;[13].length <= or add a semicolon before opening bracket
// Is interpreted as:
const mishmash = 13 + 'world';
[13].length;
// Or
// EXAMPLE
const mishmash = 13 + 'world'
([13].length)
// TypeError: "world" is not a function
// Is interpreted as:
const mishmash = 13 + 'world'([13].length)
// FIX:
const mishmash = 13 + 'world'; // <= Add semicolon here
([13].length)
// ;([13].length) <= or add a semicolon before opening parenthesis
// Is interpreted as:
const mishmash = 13 + 'world';
([13].length);
Rule no.2
ASI will add a semicolon when it encounters a closing curly brace (}) where it is not allowed by rules grammar. In this case, ASI will add a semicolon before the closing bracket.
// This is not valid, but ASI will intervene nonetheless
{ 0
2 } 8
// Is interpreted as:
{ 0;
2; } 8;
// Or, a valid example where ASI will also intervene
{ foo: 'barr' }
// Is interpreted as:
{ foo: 'barr'; }
Rule no.3
When JavaScript parses reaches the end of the file with your code ASI will also add a semicolon.
// EXAMPLE
const word = 'Hello'
const date = new Date().getFullYear()
console.log(`${word} from ${date}.`)
// Is interpreted as:
const word = 'Hello';
const date = new Date().getFullYear();
console.log(`${word} from ${date}.`); // <= Rule no.3
Rule no.4
Another situation when semicolon is added is when there is a return
statement on a separate line.
// EXAMPLE
function sayHi() {
return
'Hello!'
}
// Is interpreted as:
function sayHi() {
return; // <= Rule no.4 - semicolon after return statement
'Hello!';
}
// NOTE:
// JavaScript assumes that end of line
// where return statement is is also end of the statement
// FIX:
function sayHi() {
return 'Hello!'
}
// Or even
// NOTE: this is not recommended
function sayHi() {
return (
'Hello!'
)
}
// Both are interpreted as:
function sayHi() {
return 'Hello!';
}
// Or
// EXAMPLE
function returnObj() {
return
{
name: 'John'
}
}
// Is interpreted as:
function returnObj() {
return;
{
name: 'John';
}
}
// FIX:
function returnObj() {
return {
name: 'John'
}; // <= New end of return statement
}
// Or
// NOTE: this is not recommended
function returnObj() {
return (
{
name: 'John'
}
)
}
// Both are interpreted as:
function returnObj() {
return {
name: 'John'
}; // <= New end of return statement
}
Rule no.5
Similarly to return
statement ASI will also add a semicolon when it encounters break
statement on a separate line.
// EXAMPLE
for (let idx = 6; idx > 0; idx--) {
if (idx % 2 !== 0) {
break
}
}
// Is interpreted as:
for (let idx = 6; idx > 0; idx--) {
if (idx % 2 !== 0) {
break; // <= Rule no.5 - semicolon after break statement
}
}
Rule no.6
When JavaScript parser encounters continue
statement ASI will also add a semicolon at the end of the line where continue
statement is.
// EXAMPLE
let x = 5
while (x > 0) {
x--
if (x % 2 === 0) {
continue
}
console.log(x)
}
// Is interpreted as:
let x = 5;
while (x > 0) {
x--;
if (x % 2 === 0) {
continue; // <= Rule no.6 - semicolon after continue statement
}
console.log(x);
}
Rule no.7
The last rule of ASI: add a semicolon when there is a throw statement on its own line.
// EXAMPLE:
function getError(message) {
if (typeof message !== 'string') {
throw 'Error: Message must be string.'
}
}
// Is interpreted as:
function getError(message) {
if (typeof message !== 'string') {
throw 'Error: Message must be string.'; // <= Rule no.7 - semicolon after throw statement
}
}
Note: The return
, break
, continue
and throw
statements are also known as “restricted productions”. Another two members of this group are also ++
and --
postfix operators.
4 common misconceptions about Automatic Semicolon Insertion
There are some misconception about Automatic Semicolon Insertion. Let’s take a look at four of them that are the most common.
ASI will change your code
This misconception is probably caused by wrong understanding of how Automatic Semicolon Insertion works. The idea is that ASI will change your code directly, that it will add semicolons right into it. This is not the case. This is not how ASI works. Yes, when JavaScript parser parses your code ASI adds semicolons where necessary.
That said, JavaScript parser doesn’t save these changes in your source code. Think about this way. When you run your code, it is stored in a memory. It is stored there until either you terminate your code or until garbage collection does its job. When any of these two things happen, any changes JavaScript parser made are gone.
Semicolons are optional
Some JavaScript developers think that semicolons are optional. Well, yes and no. In the terms of JavaScript language, semicolons are not optional. There are specific situations where semicolons are required. These situations are defined by the rules we discussed above. If semicolons were optional these rules would not exist.
If those rules didn’t exist, Automatic Semicolon Insertion would have no purpose. It would not even work. These rules do exist and ASI does work. So, this is not true. Therefore, semicolons are not optional. That said, semicolons are optional when it comes to you and your code. JavaScript lets you decide whether you want to use them or not.
If you decide not to use them, JavaScript, or ASI, will add them when it is necessary. Otherwise, it will let your code as it is. So, are semicolons really optional? The only correct answer is, as usually, that it depends on the point of view.
Strict mode turns off ASI
The second misconception about ASI is that you can turn it of with strict mode. This doesn’t work. You can put as many 'use strict'
statement across your code as you want and ASI will not care. The only way you can turn off, or avoid, this feature is to make sure that you put semicolons on all places where they are required.
When you do this, add semicolons where they are required, Automatic Semicolon Insertion will have no reason to intervene. The problem is that you have to know exactly where to put a semicolon. One solution is to learn the rules. Second option is to put semicolons everywhere. This will make it much harder to miss a semicolon where it should be.
Third solution is to outsource it. There are tools you can use that will warn you get into a situation where semicolon is required. Three most popular tools for this are jshint, jslint and eslint. These tools are very popular and it is very likely there will be a plugin you can install in your favorite IDE. This will make implementation easy.
Using semicolons everywhere is safer
The last common misconception is that using semicolons everywhere is safer. The idea is that this will help you avoid bugs in browser JavaScript engines. This is also supposed to protect you from compatibility issues between browsers. The problem is that while this idea may work in theory, it doesn’t really work in practice.
All existing browsers implement the specification of JavaScript with respect to how ASI works. What’s more, JavaScript, and browser JavaScript engines, have been around for a long time and any bugs that may have existed are long gone. What this means is that you don’t have to worry about whether all browsers are compatible with ASI.
The only thing you need to know is this. All browsers that implemented JavaScript engine also follow the same rules we discussed today. Also, remember that these rules of ASI were created by creators of JavaScript. So, don’t worry that missing semicolons and ASI will lead to bugs. It will not.
So, with semicolons or without
It is time for the most important question. Should you use semicolons or not? The answer is that it depends. It depends mostly on your personal preference. Your JavaScript code will work with semicolons as well as without them. Well, except those few situations with restricted productions, parenthesis and brackets and end of file we discussed.
In those rare cases it will be necessary to add semicolons to ensure your code will work properly. Knowing about the rules we discussed will help you recognize where you really need to add a semicolon and when not. You can also adjust how you write your code. For example, you should stop writing return
statements on one line and returned value on another.
Also, you should never start a line with parenthesis. This can cause JavaScript parser to confuse statement with function call or array reference. If you do need to use parenthesis, or square brackets, at the start of the line? Add a semicolon right before the opening parenthesis or bracket.
Aside to those special cases, it is solely up to you and your preference whether you want to use semicolons or not.
Conclusion: Automatic Semicolon Insertion in JavaScript Made Simple
Automatic Semicolon Insertion can be difficult to grasp. I hope that this tutorial helped you learn about what it is and how it works. I also hope it helped you understand the rules where semicolons are required. Now, it is up to you to decide whether you want to use semicolons in your code or not.
If you decide to omit them, remember what situations to watch out for so you can avoid potential troubles. Be careful when you work with return
, break
, continue
and throw
statements and ++
and --
postfix operators, especially with return
. If you want to return some value make sure to add it on the same line as the statement.
Next, remember to never start a new line with opening parenthesis or brackets. These two can confuse JavaScript parser into thinking that you want to do a function call or reference an array. Lastly, take a look at the tools we discussed: jshint, jslint and eslint.
These tools will help you test your code and make it easier to spot when semicolon is required. This will help you avoid potential issues. If you decide to use semicolons? That’s okay as well if that’s what you like and feel comfortable with.
If you liked this article, please subscribe so you don't miss any future post.
If you'd like to support me and this blog, you can become a patron, or you can buy me a coffee 🙂