As with many other things in JavaScript Automatic Semicolon Insertion is usually not a problem but it can occasionally bite you if you are unaware of it. What Automatic Semicolon Insertion does is really simple. It basically boils down to semicolons being optional in JavaScript and the parser injecting them when it is appropriate. That might sound very nice, after all you can leave semicolons out and the right thing will happen. For example the following code, without a single semicolon, is completely valid and will print a sum of 3 as expected:
1: console.log(add(1, 2))
2:
3: function add(x, y) {
4: var sum
5: sum = x + y
6: return sum
7: }
What basically happens is that the JavaScript parser adds a semicolon at the end of each line if that doesn’t cause the syntax to become invalid. See section 7.9.1 of the ECMA-262 standard or read it online here.
Now that might sound great but it turns out that Automatic Semicolon Insertion can cause some interesting issues
JavaScript style rules
One thing you might have noticed that the normal style of writing JavaScript is different than that of C# or Java. Compare the JavaScript code above with the same C# code below:
1: public int Add(int x, int y)
2: {
3: int sum;
4: sum = x + y;
5: return sum;
6: }
Besides the obvious difference with the typing and the required semicolons the open curly brace for the add function is on the same line as the declaration in JavaScript and the next line in C#. While the JavaScript conventions would work fine in C# the reverse is not always the case. If we reformatted the JavaScript to the following the code, in this case, would still run fine.
1: function add(x, y)
2: {
3: var sum
4: sum = x + y
5: return sum
6: }
However if we would return an object literal and format our code the same way we would run into a problem. Consider the following code:
1: console.log(add(1, 2))
2:
3: function add(x, y) {
4: var sum
5: sum = x + y
6:
7: return
8: {
9: sum: sum
10: }
11: }
You might expect this to print an object with a property sum containing the value 3. However the code prints “undefined”. Compare that with the following code that is only formatted differently:
1: console.log(add(1, 2))
2:
3: function add(x, y) {
4: var sum
5: sum = x + y
6:
7: return {
8: sum: sum
9: }
10: }
This will print the expected object with a sum of 3.
Blame JavaScript Automatic Semicolon Insertion
This unexpected behavior is caused by semicolon insertion. instead of the code you most likely think will execute the following executes:
1: console.log(add(1, 2));
2:
3: function add(x, y) {
4: var sum;
5: sum = x + y;
6:
7: return;
8: {
9: sum: sum
10: };
11: }
Notice the semicolon after the return statement?
That actually means return nothing, i.e. undefined, and just have some unreachable code on the next few lines. That is completely valid so that is what happens
Best practices
The general advice, even though it doesn’t protect you is to always add semicolons and not leave it up the the JavaScript parser. It doesn’t really help a lot because the parser will still inject semicolons of it thinks it is appropriate. So the only real solution is to use the JavaScript formatting conventions and ensure that the open curly brace of the object literal is after the return statement. That way adding a semicolon there is invalid and you can be sure the right thing happens.
Unfortunately ‘use strict’ doesn’t help here either. It will prevent some errors but it doesn’t make semicolons required
Enjoy!