Using JSLint to Refine Your Code

JavaScript is an increasingly popular language thanks to the proliferation of web apps and the adoption of HTML5. Part of JavaScript’s appeal is the ease by which one can begin writing useful and fun stuff with it. There’s no need for heavyweight integrated development environments (IDEs) or third-party apps. Just open any text editor, save the file, and open it in a web browser.

JavaScript’s lure can easily turn into a trap for novice programmers. The malleability of the language can create monstrous bugs in sophisticated scripts. For example, a missing local variable declaration can mysteriously manifest itself elsewhere on the page by altering global variables.

Enter JSLint. According to its website, JSLint is a “JavaScript Code Quality Tool.” Its author, Douglas Crockford, is well known for his work on the development of JavaScript (also known as ECMAScript) and JSON. JSLint helps JavaScript programmers by making sure certain coding conventions are followed. JSLint is based on the premise of strict mode, which is available in the fifth edition of the ECMAScript standard. With strict mode, you are making your code run with a set of more restrictive rules than normal.

Using JSLint

Let’s run through an example usage of JSLint. We are writing a simple jQuery plugin that displays a message specified in the msg parameter with a prefix. The prefix is hidden if we pass the value false through the type parameter.

(function ($) {
    $.fn.loading = function(msg, type, cssClass){
        var prefixes = {
            warning: 'Warning: ' + msg,
            error: 'Error: ' + msg,
            info: 'Info: ' + msg,
            warning: 'Caution: ' + msg,
        };
        if (type) {
            concatMsg = prefixes[type];
        } else {
            concatMsg = msg;
        }
        $(this).each(function()  {
            var tis = $(this)
            if (msg == false) {
                tis.html('');
            } else {
                tis.html(concatMsg);
            }
        });
     }
})(jQuery);

Although this piece of code works fine as a plugin for jQuery, when you use it in Firefox or Chrome, you can see that there are some glaring mistakes and some very subtle ones. Instead of spending your mental energy digging out the problems, let’s use JSLint to help us. Copy the function code into the text area on the JSLint site and click the “JSLint” button. Some of the resulting JSLint output is shown in the figure below.

The first error pointed out by JSLint is that the "use strict" statement is missing. This error indicates that the function is not executed in strict mode. To correct this error, enable strict mode by adding the following string literal to the beginning of the function body.

    'use strict';

After enabling strict mode, click the “JSLint” button again. The reported error of the missing "use strict" should be gone. We can now move on to the next error, shown in the following figure. This error deals with whitespace, and is more cosmetic than functional. Since this is not an actual error, you can safely ignore it.

You can choose to stick with no space after the function keyword, and suppress the error message by scrolling to the bottom of the page and switching the “messy white space” option to true. For now, however, we want to keep the default behavior because this option also checks for other whitespace issues as we will see later.

Also notice that the second and third errors reported by JSLint are also on the same line but at different positions. Looks like a space between the closing parenthesis and the opening brace is also recommended by JSLint, so fix that now.

By clicking the “JSLint” button again, we see that the next problem is on line 8, at position 39. The prefixes object literal contains two identical warning properties, which is obviously a mistake. Let’s correct the problem by replacing the second occurrence of warning with caution.

Without clicking the “JSLint” button again, let’s look at the next error, shown in the following figure. The object literal contains a trailing comma. Browsers such as Chrome and Firefox may be tolerant of such mistakes but Internet Explorer does not take too kindly to such transgressions. To correct the problem, simply remove the comma.

The next two errors indicate that concatMsg was used before it was defined. When a variable is not defined in the current scope, JavaScript checks the enclosing scopes to see if it was defined elsewhere. If you are using code from a third-party source that happens to define this exact variable in the global scope, it can take you countless, hair-pulling hours to find the bug. Fortunately, with JSLint, we are able to nip the problem in the bud.

While fixing this problem, we can also refactor our code. Since the default value of concatMsg is msg, we can assign this value immediately and change it later if need be. The code for concatMsg can now be rewritten as shown below.

var concatMsg = msg;
if (type) {
    concatMsg = prefixes[type];
}

Next, we encounter the same whitespace issue as earlier, which can be corrected in the same way. Next, JSLint reports that a semicolon is missing. This message is shown below. Without the semicolon, JSLint assumes that the statement is never terminated. That is why it saw if while expecting a semicolon. While the language specification says that the ending semicolon is optional, it is good practice to include it. This is another area where sloppy coding can lead to hard-to-find bugs in large scale productions. By linting our code, we can fix such problems quickly and easily.

The following error is another good one. There are equality and strict equality checks in JavaScript. In our code, by not checking for strict equality the plugin behaves the same if either an empty string or the Boolean value false is specified as the first parameter. To correct the error, use the strict equality operator.

This is a good time for us to click the “JSLint” button again. The first error, shown below, is reported at line 10. JSLint seems to think that another best practice for writing JavaScript is to group variable declarations together. Although concatMsg is right after prefixes, JSLint prefers that you group the variable declarations in a single statement, separated by commas.

The next error is another cosmetic suggestion by JSLint. The fact that there is one more space than the expected number is pretty trivial at first glance. However, indentation problems can lead to bugs that are hard to catch in large scripts. For consistency, move the closing brace back into place by removing the extra space.

The next problem reported by JSLint is similar to what we have seen before, but it is manifested in a different form. JavaScript functions can be assigned to variables. As with any other variable assignment, JSLint expects a terminating semicolon.

Finally, two problems are reported at the last line, as shown below. The first problem is a suggestion to place the closing parentheses after the closing one behind jQuery because it leaves no ambiguity that you want the function definition to be a closure. The second problem is that in JSLint’s view, the variable jQuery is not present, although it might have been included in the web page by linking to a jQuery file. To address this issue, type jQuery into the bottom text field.

If you run JSLint again, it will detect that the function accepts three parameters. However, in this example, the third parameter is never used. There are two approaches you can take here. The first one is to remove the parameter since it is never used. The second option is to toggle the JSLint property “unused parameters” to true, as shown below. Choose this option only if you really want to keep the parameter in the function signature for some reason.

After using JSLint to improve our code, the final product is shown below.

(function ($) {
    'use strict';
    $.fn.loading = function (msg, type, cssClass) {
        var prefixes = {
            warning: 'Warning: ' + msg,
            error: 'Error: ' + msg,
            info: 'Info: ' + msg,
            caution: 'Caution: ' + msg
        }, concatMsg = msg;
        if (type) {
            concatMsg = prefixes[type];
        }
        $(this).each(function () {
            var tis = $(this);
            if (msg === false) {
                tis.html('');
            } else {
                tis.html(concatMsg);
            }
        });
    };
}(jQuery));

JSLint Directives

JSLint directives allow you to define variables and provide other options to JSLint from directly within the source code. This frees you from having to set the JSLint GUI options repeatedly. For example, the comments in the following example define a global variable named jQuery and set the “unparam” option to true.

/*global jQuery*/
/*jslint unparam: true */
(function ($) {
    ‘use strict’;
…
}(jQuery));

Conclusion

In this short example, JSLint has pointed out some critical errors and some seemingly insignificant ones. The fact that JSLint helps us catch these issues before we actually run the code is hugely beneficial in terms of developer productivity and application quality. If you are serious about writing production quality code, always run it through JSLint before pushing it to the server. JSLint is even contained in a single JS file, so you can download it use it offline too!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Simon Males

    JSHint is also good, installable via Node JS package manager:

    $ npm install jshint

  • http://blog.rojakcoder.com/ Chee How Chua

    That’s cool. Seems that there are various JSHint plugins for different editors. It’s a good alternative if you don’t fancy repeated copy-and-paste actions.

  • Michael Hall

    excellent article, i understood almost all of it, i’m good with jQuery but i have little experience writing jQuery functions. I also didn’t know you could download JSLint. Javascript rocked before jQuery, and the fact that jQuery is javascript prooves this point, lol. I haven’t use JSLint more than once or twice for trivial javascript snippets, becuase i could not make sense of some of ther errors/suggestions, can you point us to a thorough but easy to understand tutorial for JSLint, or perhaps cover it from a first time user’s perspective. I’d also like to thanks Douglas Crockford for all his contributions to javascript, he’s got some excellent vids over at yahoo. I also hope you guys put up a lot of tuts on how to write javascript the ‘right way’ for beginners as well, as they all have to start somewhere, preferably with excellent code and tuts so they don’t have to unlearn as I did, since I’ve been coding in JS for at least 10 years.

    • http://blog.rojakcoder.com/ Chee How Chua

      Glad you found it useful. That’s an interesting suggestion for the “right way” to write JavaScript. I’ll probably bring it up to the managing editor.
      As for a thorough (and easy to understand) tutorial for JSLint, I am not aware of such a valuable resource. It’s probably something I can try to tackle myself. :)

    • http://blog.rojakcoder.com/ Chee How Chua

      Michael, I’d like to point you to two articles written by James Edwards: http://jspro.com/raw-javascript/adding-micro-constructors-to-a-modular-design-pattern/ and http://jspro.com/raw-javascript/modular-design-patterns-in-javascript/
      I use the methods described in the second article extensively myself. I think that adopting these techniques are as good a starting point as any to begin writing JavaScript the “right way”.

  • http://www.brothercake.com/ James Edwards

    There are some odd ambiguities in JSLint.

    For example, it says you should use strict equality instead of (msg == false) and yet it’s quite happy with if(type) which is potentially subject to the same automatic type conversion issue as the problem it raised, and should be if(typeof(type) != ‘undefined’)

    Similarly, the whitespace issues it raises are, in some cases, purely matters of style, and in other cases, actually quite important, yet it mixes them up as though they’re all equally important.

    JSLint is definitely a useful tool, but a great deal of what it says is arbitrary or subjective, and it would be a much better tool if it differentiated more clearly, so that less experienced coders don’t waste their time correcting things that aren’t wrong.

    • http://blog.rojakcoder.com/ Chee How Chua

      I agree that parts of what the tool is checking for is subjective. But with JavaScript being such a flexible language, without the tool, I would argue that less experienced coders would be writing code of even lesser quality. I guess that what the tool helps to do is to establish a baseline of consistency among programmers, and once they get more experience, they can go on to tweak the settings to their own fancy.

      Furthermore, determining which parts are subjective and which parts are not, is in itself a subjective exercise, is it not?

      However, there is one thing that I really don’t understand and that is the use of the ++ operator in for loops. In this case, I would agree that it might throw a beginner off by implying that it is “wrong” to write ++ in loops.

      With regards to the if (type) clause, I would say that if (typeof(type) != ‘undefined’) is not sufficient, since if (type) checks for a few things at one go (empty string, numeric 0, boolean false, null, and undefined variables). If we were to check for everything separately, the code could be overly verbose.