A Tale of Three Linters
Even I will admit that Javascript an ugly duckling, and I love Javascript. Just about every other language out there has coalesced around a set of stylistic conventions for how code is supposed to be formatted. It's a tribute to the weirdness of Javascript that this hasn't happened. Every style out there has genuine trade-offs between readability and consistency, and thus even style guides and the linters that enforce them are Balkanized into different camps. In my travels, I've noticed 3 camps
The Javanados (The ESLint camp[1])
When I'm explaining what I do to recruiters and family members, one of the conversations I have most often is the one that goes, "I write mostly Javascript these days! No, no relation to Java. The names sound the same, but they're totally different. Yeah, I know it's confusing."
There's some historical reason for the naming. Back when the most popular programming language in the world was Visual Basic, Microsoft created a simplified version called VBScript that could run inside of Internet Explorer. In reaction, Brendan Eich whipped up a language on behalf of Netscape to do the same thing, but that wouldn't be controlled by Microsoft. Since Java was rising up as the great competitor to Visual Basic, Brendan gave the language a Java-like patina, and Netscape worked out a deal with Sun to call it .... Javascript!
While the two languages are not really all that related, folks in the Javanado camp believe that Javascript should be styled to look as much like Java as reasonably possible. Thus:
- While Javascript makes no distinction between single- and double-quoted strings, It's better to always use double-quoted strings, because that's what Java uses.
- While ending lines in semicolons is not strictly necessary in Javascript (more on that later), they are necessary in Java, so they should be used in Javascript as well
- Lines ought to be indented with 4 spaces, because that's customary in Java.
- Functions that create objects ought to be invoked using Javascript's "new" syntax where possible, because that's what Java object creation looks like.
Let me explain that last point. Unlike Java, Javascript has no built-in notion of a "class". It simply has functions and objects. Rather than calling a constructor, you initialize an object like:
function buildDog(name, age) {
return {
age: age
name: name
bark: function() {
alert('woof')
}
}
}
var fido = buildDog('fido', 7)
However, Javascript also supports a syntax which resembles the Java syntax for calling a constructor. It looks like this
function Dog(name, age) {
this.name = name
this.age = age
}
Dog.prototype.bark = function() {
alert('woof')
}
var fido = new Dog('fido', 7)
There's a few more nuances, but essentially, by calling the function with the "new" keyword, it's invoked as:
function Dog(name, age) {
this = (object that references Dog.prototype) //implicitly added when function invoked with 'new' keyword
this.name = name
this.age = age
return this //implicitly added when function invoked with 'new' keyword
}
There's various back and forth on these two styles. On one hand, the simple buildDog function is a lot more intuitive and just as powerful. On the other hand, the fido = new Dog('fido', 7) syntax for actually creating a dog is a little more explicit in what it's doing.
The Crockfordians (the JSLint camp)
In the early days, there was a sense that Javascript wasn't a real programming language. It was a toy suitable for children and managers. It was for writing form validations and sparkling hover effects. Douglas
Crockford changed this with his seminal book, "Javascript: the Good Parts".

He brought it to the public attention that underneath the quirks and weirdnesses of javascript, it also had some very, very powerful features. He argued that with its functional closures and prototypal inheritance, it is the closest thing to a mainstream Lisp we were going to get.
In addition to advocating for the power of Javascript, Crockford advocated for a strict Javascript coding style to minimize the quirkiness. Javascript will do some strange preprocessing things to your code. Take for example, variable hoisting
If you write code that looks like this:
function printSomeNumbers {
var x = 0;
console.log(x);
var y = 3;
console.log(y);
}
Javascript will "hoist" all the variable definitions to the beginning of the function. It will rewrite this code as
function printSomeNumbers {
var x, y = undefined;
x = 0;
console.log(x);
y = 3;
console.log(y);
}
From a little browsing around the internet, it appears that nobody is entirely sure what purpose this behavior was intended to accomplish. Most likely, Brendan Eich was really going after function hoisting (ie, all functions get hoisted to the top, so you never accidentally invoke a function that isn't declared yet). It was just easier to make every variable behave like this. It's mostly harmless, it just means that you can reference a variable before its declaration, and rather than not existing, it will exist with a value of undefined
Crockford believed that you shouldn't give javascript the opportunity to do this kind of implicit code rearranging. You should preempt it declaring all your local variables in the first line of your function, like:
function printSomeNumbers {
var x = 0, y = 3;
console.log(x);
console.log(y);
}
By the same reasoning the Crockfordians believe it is always better to use plain ol' functions for creating objects, and avoid the "new" keyword entirely, since new implicitly adds extra behavior to the function
The Lazy ones (the standard.js camp):
Possibly the weirdest quirk of Javascript is its automatic semicolon insertion (ASI). The rule goes something like this
- Javascript (like Java and C) requires that each line end in a semicolon
- However! If you forget the semicolons, javascript will automatically insert them for you before running your code
- It works like this. As the javascript engine goes through parsing your code, when it encounters a new line, it first tries to run the next line as a continuation of the previous line. If it finds that this doesn't result in valid javascript, it goes back to the newline character and inserts a semicolon right before it.
For example:
var a = 1
var b = 2;
The javascript parser first tries to run this as var a = 1 var b = 2;. This is not valid javascript, so the parser inserts a semicolon before the new line, ie
var a = 1;
var b = 2;
However, in the case of
var a = 1 +
3;
the parser will first try to run it as var a = 1 + 3;. This is valid, so no semicolon gets inserted.
According to the Crockfordians, this is javascript mutating your code in quirky, unexpected ways, and thus it should always be rejected. To the Javanados, Java and C have a semicolon at the end of each line, so Javascript should do the same.
However, to lazy Python and Ruby fans, this is all wrong. There is no reason to pepper your code with a bunch of unsightly semicolons, and that goes double in a language that doesn't even really need them.
Ah, but this style has a disadvantage: There is one situation where Automatic Semicolon insertion can bite you in the britches. If you begin a new line with a [, (, or `, it can sometimes be a valid continuation of the previous line in ways you wouldn't expect.
Consider
var a = 1
var b = 2
var c = a + b
[a, b, c].forEach(function(a){console.log(a)})
The javascript parser will NOT do what you think it should do here. Instead, it will try running the last 2 lines together:
var c = a + b[a, b, c].forEach(function(a){console.log(a)})
THIS IS SYNTACTICALLY VALID JAVASCRIPT, though it will throw a runtime error.
So, rather than warning you that you missed a semicolon at the end of each line, the Standard.js linter needs to warn you that you need a semicolon every time you begin a line with a "[", "(" or "`" character.
var a = 1
var b = 2
var c = a + b
;[a, b, c].forEach(function(a){console.log(a)}) // works as expected
In reality such situations are rare, but if you aren't aware of them or don't have a linter to catch them they can be real head-scratchers. The Crockfordians and Javanados would argue that even the possibility of such mistakes is enough reason to just write the semicolons.
In general, the Standard.js linter follows a philosophy of minimalism. Semicolons should be left to ASI unless necessary. Indents ought to be two spaces, because that's more compact. Strings ought to be single-quoted, because it saves your pinkie a stretch to the "Shift" key.
With the advent of ES6/ES2015/ES7 etc, most of the distinctive bugbears of the Crockfordian school are moot points. In ES6, variables are declared with the let keyword, which avoids the variable-hoisting behavior. ES6 also introduces a genuine class syntax, which is usually preferable to both the old styles. As a result, the Crockfordian school seems to have more or less fallen off the map.
I admit for myself, I slightly prefer the aesthetics of standard.js, but I realize I'm in the minority, and wasting time trying to argue it against the Javanado style is the worst sort of bikeshedding.
More than any linter, I think the true game-changer for code styling is prettier. This is the library that doesn't just complain you about formatting your code, it automatically rewrites it to make the style corrections, while guaranteeing the same behavior.
I find that the better way is to just have my environment set up so that it runs prettier on my files after every save. It makes nitpicking about semicolons and single quotes in code review a moot point.
I'm torturing the metaphor a little by calling ESLint the linter of the Javanados. ESlint is totally customizeable. It can be configured to any linting style. However, the default settings favor Javascript that looks like Java. ↩︎
Subscribe to Axten Software
Get the latest posts delivered right to your inbox