Opinions versus Fact
This article is about my "opinion." Semicolons should be included when writing JavaScript. The simple fact is that I do not have any quantitative or qualitative data to prove one is better than the other. I know what I prefer.
Programs must be written for people to read, and only incidentally for machines to execute.
-- Abelson and Sussman
There are two schools of thought on whether to insert semicolons into code as good practice. The question becomes, is it a best-practice:
- To use semicolons as a readability feature?
- To only use semicolons in areas where automatic semicolon insertion does not place them?
School of Thought: 'Always Use Semicolons'
This thought says that developers should always use semicolons, even in areas where automatic semicolon insertion (ASI) would normally take care of things.
The assumption is that the ASI will never be 100% reliable, but also liable to change with each new version of JavaScript. If the ASI feature is altered or changed down the line, code that did not use semicolons may be operating under deprecated functionality.
School of Thought: 'Never Use Semicolons'
The second school of thought is that semicolons should only be used in cases where they are absolutely required.
The assumption is that the documentation for the ASI clearly states the cases in which the feature is implemented. Because the ASI feature will take care of the insertion negates the need to add superfluous punctuation.
The word never in the title, as is almost always the case, is not to be taken literally. There are many instances in JavaScript where semicolons are absolutely required, instances that the ASI feature will not take care of.
This school of thought declares the concept as a way to encourage good coding practices.
Definitions
{ }
: Curly Brackets
[ ]
: Square Brackets
( )
: Parentheses
Automatic Semicolon Insertion (or ASI)
The reason semicolons are sometimes optional in JavaScript is because of ASI. It does not mean that actual semicolons are inserted into the code.
ASI is more of a set of rules used by JavaScript that will determine whether or not a semicolon will be interpreted in certain spots. When there is a place where a semicolon is needed, it quietly adds it behind the scenes.
For convenience, however, such semicolons may be omitted from the source text in certain situations. These situations are described by saying that semicolons are automatically inserted into the source code token stream in those situations.
- ECMAScript Language Specification
It is important to know the rules that power semicolons, to avoid writing code that will generate bugs because JavaScript does not behave in an expected manner.
The JavaScript parser automatically adds a semicolon when, during the parsing of the code, it comes across a few particular situations:
- When the next line starts with code that breaks the current one (code can spawn on multiple lines).
- When the next line starts with a curly bracket,
}
, closing the current block. - When the end of the code is reached.
- When there is a
return
,break
,throw
, orcontinue
statement on its own line.
Cheat Sheet: Semicolon is Needed
Required
The semicolon in JavaScript is only required when two or more statements are on the same line.
// Semicolon required, but optional before the line break
var i = 0; i++
// Semicolon optional
var i = 0
i++
Optional
The semicolon in JavaScript is used to separate statements. However, it can be omitted if the statement is followed by a line break (or there is only one statement in a block, generally identified by curly brackets { }
).
Here are some comment types of statements ...
// Variable declaration
var i;
// Value assignment
i = 5;
// Value assignment
i = i + 1;
// Value assignment
i++;
// Declaration and Assignment
var x = 9;
// Variable declaration, assignment, and function definition
var fun = function() { // ... };
// Function call
alert('bob');
All of these statements end with a semicolon, but none of them must. This article is about whether or not it is a **good habit to terminate each statement with a semicolon."
Avoid
After a closing curly brackets
A semicolon should not come after a closing curly bracket }
. The only exceptions to this rule are assignment statements, such as let a = { // ... };
.
// No semicolons follow ...
if () { // ... } else { // ... }
for () { // ... }
while () { // ... }
// Function statement
function b(argument) { // ... }
After a closing parenthesis of an IF, FOR, WHILE, or SWITCH statement
This is no real harm in putting a semicolon after the { }
of an IF-STATEMENT. It will be ignored and there might be a warning that it is not needed. However, a semicolon where it does not belong is a very bad idea ...
if (value === true); { alert('Yes!') }
// Is equivalent to ...
if (value === true) /* DO NOTHING */;
alert('Yes');
This code will always alert 'YES!', but not because value
is true
, but because of the semicolon. It makes JavaScript believe that there is an empty bracket there. Everything to the right is of the semicolon is treated as if it no longer belongs to the IF-STATEMENT and this independent of it.
And now, the exception ...
Of course, there is an exception.
An important issue is inside the parentheses ( )
of a FOR-LOOP ... here, semicolons only go after the first and second statement, never after the third.
// Correct Syntax
for (var i = 0, len = 10; i < len; i++) { // actions }
// Syntax Error
for (var i = 0, len = 10; i < len; i++;) { // actions }
Code That Does The Unexpected
Without semicolons, there are several cases where the code can behave in an unusual manner.
Given code like this ...
const word = 'WORD'
const another = 'ANOTHER'
['b', 'o', 'b'].forEach(letter => console.log(letter))
... the error Uncaught TypeError: Cannot read property 'forEach' of undefined
occurs because the first rule tries to interpret the code above as ...
const word = 'WORD'
const another = 'ANOTHER'['b', 'o', 'b'].forEach(letter => console.log(letter))
Next, given code like this ...
(1 + 2).toString()
The expected "3"
occurs as an output.
However, if this code is extended ...
const a = 1
const b = 2
const combined = a + b
(a + b).toString()
... TypeError: b is not a function
is triggered as an exception, because Javascript tries to interpret the code as ...
const a = 1
const b = 2
const combined = a + b(a + b).toString()
Examining one of the classic missing semicolon examples, the code looks like this ...
(() => {
return
{
result: 'bob'
}
})()
The expectation would be that the return value of this IIFE would be an object that contains the result
property with a value of 'bob'
.
This is not the case.
Instead, it is undefined
, because JavaScript inserts a semicolon after the return
.
The correct way to write this code has the opening curly bracket right after the return
...
(() => {
return {
result: 'bob'
}
})()
Checking the rules above, number 4 is the one that is broken here.
One more example gives code that looks as if a console.log
fires with '0' being the output ...
41 + 1
-1 + 1 === 0 ? console.log('0') : console.log('42')
... however, it gives the "Answer to the Ultimate Question of Life, the Universe, and Everything," or 42 because rule 1 above interprets this code as ...
41 + 1 -1 + 1 === 0 ? console.log('0') : console.log('42')
Humor
Conclusion
This article documents my "opinion." Semicolons should be included when writing JavaScript.
I suspect that either path can cause issues when a semicolon, or lack thereof, causes issues. As individual developers get to know JavaScript, leaving the semicolons out can potentially cause issues that become hard to decipher. As experience grows and we understand what JavaScript does, they could be left out. My only issue with this path is that, at some point, a less experienced developer working with the code could again see issues.
The simple fact is that I do not have any quantitative or qualitative data to prove one is better than the other. I know what I prefer ... include semicolons when writing JavaScript.