Control the Complexity of Your JavaScript Functions with JSHint

Published

September 25, 2012

Reading time
4 min read

New JSHint Features

Many of you are aware of the JSHint code quality tool that has been around for the past couple of years. As of recently, the following new options that have been added regarding the complexity of a function.

  • maxparams
  • maxdepth
  • maxstatements
  • maxcomplexity

Parameters, Depth, and Statements

By reducing the number of parameters, the number of nesting, and the number of statements in your function you can dramatically increate the readability and modularity of your code.

The following piece of code shows using the maxparams, maxdepth, and maxstatements to warn us of possible issue with our functions.

/*jshint maxparams:3, maxdepth:2, maxstatements:5 */
/*global console:false */

(function( undefined ) {
    "use strict";

    function test1( arg1, arg2, arg3, arg4 ) {
        console.log( "too many parameters!" );
        if ( arg1 === 1 ) {
            console.log( arg1 );
            if ( arg2 === 2 ) {
                console.log( arg2 );
                if( arg3 === 3 ) {
                    console.log( "too much nesting!" );
                    console.log( arg3 );
                    console.log( arg4 );
                }
            }
        }
        console.log( "too many statements!" );
    }

    test1( 1, 2, 3, 4 );
}());

JSHint gives an error that too many parameters were used because we limited maxparams to 3 and the code accepted 4 parameters. An error occurred because the depth of logic is too deep because we limited it to a maxdepth of 2. We will also get an error about the number of lines in our function because we limited maxstatements to 5 and we have many more than that.

Cyclomatic Complexity

A less commonly known software metric used to evaluate functions is Cyclomatic Complexity. Like it sounds, it's purpose is to calculate the overall intricacy of a function and to give a score that reflects it's complexity.

"The cyclomatic complexity of a section of source code is the count of the number of linearly independent paths through the source code." --//en.wikipedia.org/wiki/Cyclomatic_complexity

In addition to the above parameters, depth, and statement metrics you can now track the overall complexity using the maxcomplexity option.

/*jshint maxcomplexity:3 */
/*global console:false */

(function( undefined ) {
    "use strict";

    function isPrime( number ) {
        var prime = true, i;

        if ( isNumber( number ) ) {
            for ( i = 2; i < number; i++ ) {
              if ( number % i === 0 ) {
                  prime = false;
              }
            }
        } else {
            prime = false;
        }

        return prime;
    }

    function isNumber( number ) {
        return !isNaN( parseFloat( number ) ) && isFinite( number );
    }

    console.log( isPrime( 109 ) );
}());

As you see above, the above function has more complexity that what we set in maxcomplexity.

You might be wondering what a reasonable maxcomplexity value is for your project. In the 2nd edition of Steve McConnell's Code Complete he recommends that a cyclomatic complexity from 0 to 5 is typically fine, but you should be aware if the complexity starts to get in the 6 to 10 range. He further explains that anything over a complexity of 10 you should strongly consider refactoring your code.

Global Options

Instead of adding these options to the top of each and every JavaScript file you an instead use a .jshintrc file in your project and JSHint should pick up those settings. This is handy if your project is large and you want some consistent settings across the board.

{
    "globals": {
        "console": false,
        "jQuery": false,
        "_": false
    },
    "maxparams": 5,
    "maxdepth": 5,
    "maxstatements": 25,
    "maxcomplexity": 10,
    "es5": true,
    "browser": true,
    "boss": false,
    "curly": false,
    "debug": false,
    "devel": false,
    "eqeqeq": true,
    "evil": true,
    "forin": false,
    "immed": true,
    "laxbreak": false,
    "newcap": true,
    "noarg": true,
    "noempty": false,
    "nonew": false,
    "nomen": false,
    "onevar": true,
    "plusplus": false,
    "regexp": false,
    "undef": true,
    "sub": true,
    "strict": false,
    "white": true,
    "unused": true
}
Web Mentions
0
0

Tweet about this post and have it show up here!