Code With Wolf


Curly Braces - Why You Need Curly Braces in JavaScript

Curly Braces in JavaScript and C

Many developers that use JavaScript do not consider JS to be their primary language. This makes me an anomaly.

After writing JavaScript and switching to most of my day in C#, the first thing I started to wonder about is what is going on with the curly braces.

In JavaScript, curly braces start on the same line as the statement. In C#, there is a line break.

The Problem

// JS
if(somethingIsTrue){    // <= curly brace on same line
   //do something...
 }
//C#
if(somethingIsTrue)
 {                    // <= curly brace on new line
   //do something...
 }

This seemed as trivial as the tab vs spaces debate.

Turns out, it’s not and the reason is something I did not expect.

JavaScript

First, let’s take a look at some properly written JavaScript code.

//JS
function doSomething(){
   return{
      name: 'Wolf',
      occupation: 'Badass Code Blogger',
      spiritAnimal: 'Pabst Blue Ribbon'
   }
}
doSomething()
// returns {
      name: 'Wolf',
      occupation: 'Badass Code Blogger',
      spiritAnimal: 'Pabst Blue Ribbon'
   } ...as expected

Now, let’s say we are a C# developer and we are writing JavaScript (an incredibly common occurrence).

We will add our curly braces on a new line just like in C# (I see this all the time…).

//JS but with '{' on a new line
function doSomething()
  {
   return
   {
      name: 'Wolf',
      occupation: 'Bad Ass Code Blogger',
      spiritAnimal: 'Pabst Blue Ribbon'
   }
}
doSomething()
// returns `Undefined`

Wat?

That literally makes no sense. Obviously you can just keep your curly brace on the same line in JavaScript, but that seems so messed up that this example doesn’t work.

And it is worse than you can imagine…

The Solution

This is actually caused by an entirely different debate.

This is due to the JavaScript compiler’s ASI or Automatic Semicolon Insertion.

This sound completely crazy, but I will explain.

Please hold off the death threats when I say this, but semicolons in JavaScript are REQUIRED.

If you search Stack Overflow and Reddit and the vast JS community you will see devs murdering other devs over this.

You may be a “not putting a semicolon in my code never hurt me” kind of dev, and that’s fine, but you are a lucky one. Leaving the semicolon addition to the ASI in the compiler can create bugs that are nearly impossible to fix. We’ll discuss this soon.

The JS Compiler Will Add Semi-colons for you... sometimes.

First, here are a few cases where the compiler will add a semicolon for you.

  1. Before a line-break when the line-break is followed by the keyword ‘var’, ‘let’, or ‘const’.

    let a = 1  // <= semicolon auto-inserted
    let b = 2  // <= semicolon auto-inserted
  2. After a terminator keyword, such as ‘return’, ‘continue’, ‘break’, or ‘throw’ if nothing follows that keyword on the same line.
if(somethingIsTrue)
{
   return // <= semicolon auto-inserted
  {
    theThingIsTrue: 'yes'// <= semicolon auto-inserted
  }  // <= semicolon auto-inserted
}  // <= semicolon auto-inserted

The above statement would return undefined because of the semicolon auto-inserted after the ‘return’ keyword.

If our curly braces would have been placed according to conventional JavaScript standards, this would have returned the object we were expecting.

Even Bigger Problem

These examples aren’t too difficult to debug, especially if you read this or understand ASI. Now let’s look at a problem bound to destroy your app for a while.

var a = 1
var b = 1+a
(function(){
   // Some code...
   // let's pretend it's an Angular component (or another framework)
})()

Now I will add the auto inserted semicolons:

var a = 1 // <= semicolon auto-inserted
var b = 1+a
(function(){
   // Some code...
   // let's pretend it's an Angular component (or another framework)
})() // <= semicolon auto-inserted

Have you spotted the problem?

JS doesn’t auto-insert a semicolon after ‘b’ is declared.

As we discussed, JS will add a semicolon after var b = 2 if the next line started with an appropriate keyword. Instead it starts with an open parenthesis which is completely allowed, because JS might just assume a is a function being invoked.

Here is where this can be a problem. If you are writing in Angular or another framework and using a lot of IIFEs, but some code is left out of an IFFE (such as an app.js), then the scenario above is essentially what your compiled code what look like.

There is certainly a chance that this can happen after your project is minified and this would be an incredibly difficult bug to detect, certainly more serious than the other examples.

tl;dr

In conclusion, the JS compiler will add semicolons in certain cases. The problem is that a typical JS developer isn’t going to always understand the nuances of the automatic semicolon insertion and won’t be thinking about them consciously while coding. The IIFE example here is a rare and extreme example, but a lot of bugs caused by ASI are exactly that. These bugs can be nearly impossible to fix, but they are also completely avoidable by using best practices.

These are the best JavaScript practices to avoid these errors. Consistently use semicolons in JavaScript as you would in C#. Also, keep your curly braces on the same line in JS (unlike C#). Luckily, if you are using Visual Studio 2017 and you auto format your code with CTRL+K+D, Visual Studio will take care of the JavaScript curly braces for you.

If you get caught in one of these ASI bugs, you may never return. It could mean your job, then your career (who is going to hire a JS dev that doesn’t use semicolons!), and then you will starve and die. Use semicolons.



© 2022 Code With Wolf