Static JavaScript parsers and errors that they will help to unlearn (Part 2)

Original author: Zack Grossbart
  • Transfer
We continue the translation of the article on static analyzers: in the last part, the author touched on such nuances as the use of == and === operators, as well as indefinite variables and late definitions, in addition, the author points out the comments that the analyzers give (for example, JSHint) with detecting such errors. In this part, we will talk about re-declaring a variable, as well as about controlling the cyclomatic complexity of the code.

Re-declaring (using) a variable
In JavaScript, you can re-declare (use) variables, but this almost always happens by accident. See:

function incrementCount(counter) {
 if (counter.count) {
 } else {
  var counter = 1;
  counter.count = counter;

In this function, we increment the count property for the presented object, but we need to add the property if it is still not there. See the bug?

This function will never add or increment a counter. The else expression will always be called, and it will redefine the argument to the counter function. Basically, this function creates a new object, assigns a property to it, and then loses the object when the function returns. She never changes the object that was presented.

This simple type will allow you to run the code without errors, but it will lead to a rather strange result.

JSHint will show the following:

test.js: line 21, col 21, 'counter' is already defined.

Braces in blocks, loops, and conditional constructions

if (false)

What will this code do - doSomething or doSomethingElse? At first glance it always seems to me that he will not execute doSomething or doSomethingElse. This is how it works in Python, but not in JavaScript. JavaScript, in the first place, will execute the line below the if statement as part of the block. Indentation doesn't matter.

The whole problem is code readability. If you don’t understand what the code will do, you will write bugs.
Python and CoffeeScript love to skip braces. This works well in languages ​​that use free space formatting, but JavaScript behaves differently. JavaScript allows you to create a lot of weird syntax, while curly braces help you avoid troubles.

if (false) {

Add brackets and your code will always be more readable. Skip them and JSHint will show you the following:

test.js: line 27, col 5, Expected '{' and instead saw 'doSomething'.

Single and double quotes

console.log("This is a string. It's OK.");
console.log('This string is OK too.');
console.log("This string " + 'is legal, but' + "really not OK.");

JavaScript allows you to define strings using single and double quotes. This is good when you have flexibility, such as in defining HTML, but additional flexibility can lead to very inconsistent code.

Google has a code style guide that always uses single quotes for strings, so they don’t need to remove double quotes in HTML. I can't argue that single quotes are better than double quotes, but I can argue that consistency is important here. Compliance makes code more readable.

JSHint will warn you about mixing quotes like this:

test.js: line 31, col 27, Mixed double and single quotes.

Copying and pasting or writing quotes incorrectly is quite simple. As soon as you put the wrong quotation marks, the rest will also start to do so, especially if several people are editing the file. Static analyzers keep quotation marks consistent and help avoid big cleanups in the future.

Cyclomatic complexity

Cyclomatic complexity is a measure of the complexity of a given block of code. Look at the code and count the number of branches by which it can work - this number is cyclomatic complexity.
For example, the cyclomatic complexity of this code is 1:

function main() {
 return 'Hello, World!';

You can trace only one branch of the execution of this code.
Let's add conditional logic:

function main() {
 if (true) {
  return 'Hello, World!';
 } else {
  return 'Hello, unWorld!';

Cyclomatic complexity has increased to 2.

Perfect code is easy to read and understand. The higher the cyclomatic complexity, the more difficult it will be to understand the code. Everyone agrees that high cyclomatic complexity is bad, but no one can come to a certain limit; 5 is good, and 100 is too much. And in the middle is too much uncertainty.

If cyclomatic complexity reaches a predefined limit, JSHint will notify you of this.

test.js: line 35, col 24, This function's cyclomatic complexity is too high. (17)

JSHint is the only one of the three verification programs that takes into account cyclomatic complexity. It also allows you to set a limit. Exceed your maxcomplexity number and JSHint will warn you. I like to set the limit to 14, but I can make it a little higher in projects where I need a lot of parsing.

In fact, the meaning of complexity is important because it tells you when to reorganize the code. When you write a long function for the first time, it matters. But when you wait six months and then return to the code to fix the bugs, you will be glad that you took the time to make it more readable.

Cyclomatic complexity is usually broken down into a list. For example, I created a calendar, and I wanted to set the correct first day of the week for each country. I had a function that looked like this:

function getFirstDay(country) {
 if (country === 'USA') {
  return 'Sunday';
 } else if (country === 'France') {
  return 'Monday';
 } else if…

I needed to cover many countries, so the cyclomatic complexity quickly jumped over the 50 mark. Although the code was pretty readable, the number of branches was huge, so my code analyzer was not happy. I eventually split the function and got complexity below my maximum. It was not an easy task for this particular case, but it is a low price for cleaner code in general.

Check everything you edit more than once

Static analyzers find bugs that you would not have discovered with simple testing. They also find bugs in the compilation process, and not during work - these are the same midnight bugs that creep in when a dozen people take up one thing. Finding all these subtle bugs without checking the code is a long and painful process.

I started this article with the statement that I always use a code analyzer, but I do not do this in one case: when I write one-time code. I like to use quick prototypes to showcase interactive ideas and help my team understand how something should work. Such prototypes are one-time codes; I don’t need to fix bugs here, because I will throw this code in a few weeks. Such a one-time code exists solely for short demonstrations, and it does not matter to me whether there are subtle bugs in it. And everything that is important to me is analyzed.

Fixing these types of bugs at the beginning of a project is fairly easy. Finding them the night before the release can drive you crazy. Code analyzers have saved my life many times, and therefore will save yours.

Also popular now: