Improve code quality with JsHint

Share:
Source Code

What is JsHint?

JsHint is a code quality tool that helps detect errors and potential problems in your javascript code.  It can be used as a standalone command line tool, or a node module to use along side your Node JS based projects.

Set Up

Let’s start by setting up an empty node js project, create a package.json file with the following:

{
  "name": "Jshint",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
  	"lint": "jshint index.js"
  },
  "devDependencies": {
    "jshint": "^2.8.0"
  },
  "author": "PentaCode",
  "license": "ISC"
}

run npm install jshint -g to install the jshint executable globally.

Next we will create a project file call index.js to test out some of the features of Jshint.

var myFunction = function() {
	var num = 0;

	//curly: This option requires you to always put curly braces around blocks in loops and conditionals. JavaScript allows you to omit curly braces when the block consists of only one statement, for example:
	while (num !== 10)
		doSomething();

	function doSomething() {
		console.log('do something');
	}

	//eqeqeq: This options prohibits the use of == and != in favor of === and !==. The former try to coerce values before comparing them which can lead to some unexpected results. The latter don't do any coercion so they are generally safer.
	if (num == 10) {
		console.log('The number is 10');
	}

	//latedef: This option prohibits the use of a variable before it was defined. JavaScript has function scope only and, in addition to that, all variables are always moved—or hoisted— to the top of the function. This behavior can lead to some very nasty bugs and that's why it is safer to always use variable only after they have been explicitly defined.
	badVar = 'bird';
	var badVar;

	//evil: This option suppresses warnings about the use of eval. The use of eval is discouraged because it can make your code vulnerable to various injection attacks and it makes it hard for JavaScript interpreter to do certain optimizations.
	var x = 10;
	var y = 20;
	var a = eval("x * y") + "<br>";
	var b = eval("2 + 2") + "<br>";
	var c = eval("x + 17") + "<br>";
	var res = a + b + c;

	//noarg: This option prohibits the use of arguments.caller and arguments.callee. Both .caller and .callee make quite a few optimizations impossible so they were deprecated in future versions of JavaScript. In fact, ECMAScript 5 forbids the use of arguments.callee in strict mode.
	function whoCalled() {
	   if (arguments.caller == null)
	      console.log('I was called from the global scope.');
	   else
	      console.log(arguments.caller + ' called me!');
	}

	[1,2,3,4,5].map(function (n) {
	    return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
	});

	//undef: This option prohibits the use of explicitly undeclared variables. This option is very useful for spotting leaking and mistyped variables.
	badVar = myUndefinedVar;

	//eqnull: This option suppresses warnings about == null comparisons. Such comparisons are often useful when you want to check if a variable is null or undefined.
	var x = 13;
	if (x === null) {
		console.log('x is null');
	}

	//node: This option defines globals available when your code is running inside of the Node runtime environment. Node.js is a server-side JavaScript environment that uses an asynchronous event-driven model. This option also skips some warnings that make sense in the browser environments but don't make sense in Node such as file-level use strict pragmas and console.log statements.

}

There are numerous mistakes in the code, and jshint will be able to identify them and let you know what the errors are.

if you open up command line and type:

jshint index.js

you will see the JsHint caught numerous errors:

index.js: line 6, col 9, Expected '{' and instead saw 'doSomething'.
index.js: line 13, col 15, Expected '===' and instead saw '=='.
index.js: line 31, col 12, Avoid arguments.caller.
index.js: line 32, col 11, Expected '{' and instead saw 'console'.
index.js: line 34, col 11, Expected '{' and instead saw 'console'.
index.js: line 34, col 23, Avoid arguments.caller.
index.js: line 38, col 16, Confusing use of '!'.
index.js: line 38, col 31, Avoid arguments.callee.
index.js: line 45, col 9, 'x' is already defined.
index.js: line 54, col 2, Missing semicolon.
index.js: line 42, col 14, 'myUndefinedVar' is not defined.

JsHint tells you the exact line and character number where the error occurred. You can get a list of error explanations from this site

Fixing the errors

Let’s try to fix all these errors, I went ahead and go through everything pointed out by jshint and here’s what I ended up with:

var myFunction = function() {
	var num = 0;

	//curly: This option requires you to always put curly braces around blocks in loops and conditionals. JavaScript allows you to omit curly braces when the block consists of only one statement, for example:
	while (num !== 10) {
		doSomething();
	}

	function doSomething() {
		console.log('do something');
	}

	//eqeqeq: This options prohibits the use of == and != in favor of === and !==. The former try to coerce values before comparing them which can lead to some unexpected results. The latter don't do any coercion so they are generally safer.
	if (num === 10) {
		console.log('The number is 10');
	}

	//latedef: This option prohibits the use of a variable before it was defined. JavaScript has function scope only and, in addition to that, all variables are always moved—or hoisted— to the top of the function. This behavior can lead to some very nasty bugs and that's why it is safer to always use variable only after they have been explicitly defined.
	var badVar;
	badVar = 'bird';

	//evil: This option suppresses warnings about the use of eval. The use of eval is discouraged because it can make your code vulnerable to various injection attacks and it makes it hard for JavaScript interpreter to do certain optimizations.
	var x = 10;
	var y = 20;
	var a = String(x * y) + "<br>";
	var b = String(2 + 2) + "<br>";
	var c = String(x + 17) + "<br>";
	var res = a + b + c;

	//noarg: This option prohibits the use of arguments.caller and arguments.callee. Both .caller and .callee make quite a few optimizations impossible so they were deprecated in future versions of JavaScript. In fact, ECMAScript 5 forbids the use of arguments.callee in strict mode.
	// function whoCalled() {
	//    if (arguments.caller == null)
	//       console.log('I was called from the global scope.');
	//    else
	//       console.log(arguments.caller + ' called me!');
	// }

	// [1,2,3,4,5].map(function (n) {
	//     return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
	// });

	//undef: This option prohibits the use of explicitly undeclared variables. This option is very useful for spotting leaking and mistyped variables.
	var myUndefinedVar = 'foo';
	badVar = myUndefinedVar;

	//eqnull: This option suppresses warnings about == null comparisons. Such comparisons are often useful when you want to check if a variable is null or undefined.
	var z = 13;
	if (!z) {
		console.log('z is null');
	}

	//node: This option defines globals available when your code is running inside of the Node runtime environment. Node.js is a server-side JavaScript environment that uses an asynchronous event-driven model. This option also skips some warnings that make sense in the browser environments but don't make sense in Node such as file-level use strict pragmas and console.log statements.
};

Use JsHint with your workflow

You can use JsHint in your development workflow very easily by hooking it up to a git commit hook or with a task runner like Gulp or Webpack. Check out the tutorials on those.

Comments Or Questions? Discuss In Our Discord

If you enjoyed this tutorial, make sure to subscribe to our Youtube Channel and follow us on Twitter @pentacodevids for latest updates!

More from PentaCode