JSHint is a tool that analyzes JavaScript source code to warn about quality problems. This post describes how to use it.
What it is
JSHint...
- detects anti-patterns and potential errors. Example: Using an assignment in the condition of an if statement.
if (x = 3) { ... }
- enforces best practices and coding styles. Example: The names of constructors must be capitalized.
There are also plug-ins for integrating development environments with JSHint. For example, a
TextMate bundle that runs JSHint whenever a JavaScript file is saved.
History. JSHint is based on Douglas Crockford’s JSLint whose initial release was in 2002. In 2011, Anton Kovalyov released JSHint and explains why he forked Crockford’s tool:
JSLint served me well for quite some time but in the past few months it has gotten uncomfortably opinionated and hostile towards your code. It is quickly transforming from a tool that helps developers to prevent bugs to a tool that makes sure you write your code like Douglas Crockford.
Installation
- Install npm, the Node Package Manager
- Use npm to install node-jshint:
npm install -g jshint
In most Unix installations, you have to prefix the above command with a sudo (“execute as super-user”), so that everything can be put where it needs to be.
The
JSHint GitHub page mentions other platforms that JSHint runs on: Rhino, Windows Scripting Host, Mac OS X JavaScriptCore.
Example
Let’s say we want to check the following file
demo.js.
function foo(x, y) {
if (x > y) return x;
bar = x * y
return
bar;
}
This command runs JSHint:
jshint demo.js --config config.json
The optional
--config allows you to configure JSHint’s operation via a
custom config file (
config.json in the command above). Such a file is in JSON syntax [1] which means that keys must be quoted and that there can be no trailing comma. The settings that can be influenced by a config file are listed later.
config.json looks as follows.
{
"predef": [ "myModule" ],
"undef": true,
"curly": true
}
node-jshint comes with a much more comprehensive
example.
Running JSHint on demo.js with the previously mentioned command produces the following errors:
demo.js: line 2, col 16, Expected '{' and instead saw 'return'.
demo.js: line 3, col 5, 'bar' is not defined.
demo.js: line 3, col 16, Missing semicolon.
demo.js: line 4, col 5, Line breaking error 'return'.
demo.js: line 5, col 5, 'bar' is not defined.
5 errors
Reasons for the reported errors:
- The then-clause of the if statement must be a block.
- Missing var before bar.
- Missing semicolon after the assignment.
- The return statement cannot be broken up into two lines [2].
- Accessing the undeclared variable bar.
Inline options
Some settings can be controlled by putting comments in the source code.
- Global variables (setting predef):
/*global DISQUS: true, jQuery: false */
Consequence: The global variable DISQUS can be read and written, jQuery can only be read.
- Other settings (see below for a list):
/*jshint evil: true, boss: true */
Config file settings
The default for all boolean settings is always
false. [Most of the text in this section has originally been taken from the JSHint source code.]
Controlling how it runs
passfail | boolean | true if checking should stop after the first error. |
maxerr | number | Stop after how many errors? Default: 50. |
Debugging
debug | boolean | true if debugger statements are allowed. These act like break points and probably shouldn’t be in shipping code. |
devel | boolean | true if logging globals (console, alert, ...) should be considered predefined. In other words: don’t complain when those are used. |
Firefox-only
iterator | boolean | true if the __iterator__ property should be disallowed. |
proto | boolean | true if the __proto__ property should be disallowed. |
ECMAScript 5 and standard-compliance
es5 | boolean | true if ES5 syntax is allowed. |
globalstrict | boolean | true if global "use strict"; is allowed (also sets strict to true). |
noarg | boolean | true if arguments.caller and arguments.callee should be disallowed. |
nonstandard | boolean | true if non-standard – but widely used – globals should be predefined (see below what that means). Currently, those are escape and unescape which are deprecated anyway – it is better to use encodeURIComponent and decodeURIComponent, instead. |
standard | boolean | true if standard ECMAScript globals should be predefined (see below what that means). Examples: Array, Date, JSON. |
strict | boolean | If true, require the "use strict"; for all code (be it file-globally or for each function individually). |
Predefined globals
These options control what global identifiers are considered
predefined by JSHint. JSHint will let you access a predefined global without having declared it beforehand.
predef | string[] | an array with the names of custom predefined global variables. |
browser | boolean | true if the standard browser (DOM) globals should be predefined. Examples: document, WebSocket, window. |
couch | boolean | true if CouchDB globals should be predefined. |
dojo | boolean | true if Dojo Toolkit globals should be predefined. |
jquery | boolean | true if jQuery globals should be predefined. |
mootools | boolean | true if MooTools globals should be predefined. |
node | boolean | true if the Node.js environment globals should be predefined. Examples: exports, global, process. |
rhino | boolean | true if the Rhino environment globals should be predefined. Examples: load, print, quit. |
wsh | boolean | true if the Windows Scripting Host environment globals should be predefined. Examples: ActiveXObject, VBArray, WSH. |
prototypejs | boolean | true if Prototype and Scriptaculous globals should be predefined. |
Style
asi | boolean | true if automatic semicolon insertion should be tolerated. If false, you are warned about all missing semicolons. |
newcap | boolean | true if constructor names must be capitalized. |
nomen | boolean | true if leading or trailing underscores should be disallowed in names. Those are often used for “privacy by naming convention” (which some consider bad practice, but there are cons and pros to it). |
onevar | boolean | true if only one var statement per function should be allowed. |
plusplus | boolean | true if increment/decrement should not be allowed. If you use this operator in a statement by itself (as opposed to inside another statement), then there is nothing bad about it. |
lastsemic | boolean | true if the semicolon may be omitted after the last statement inside a one-line block. |
sub | boolean | true if inefficient property access is allowed. For example, obj["prop"] is less efficient than obj.prop. This option never complains about computed values inside square brackets. |
trailing | boolean | true if trailing whitespace is forbidden. |
white | boolean | true if strict whitespace and indentation rules apply. |
Correctness
bitwise | boolean | true if bitwise operators should not be allowed (which are likely typos). |
boss | boolean | true if advanced usage of assignments should be allowed. Example: An assignment inside the condition of an if statement (which is likely a mistyped equals operator). |
curly | boolean | true if blocks (in curly braces) should be required where one can also put single statements (as part of if statements, loops, etc.). |
eqeqeq | boolean | true if === should be required. |
eqnull | boolean | true if == null comparisons should be tolerated. |
evil | boolean | true if eval should be allowed. |
expr | boolean | true if an expression should be allowed to be the complete program (in a file). |
forin | boolean | true if for...in statements must filter via hasOwnProperty(). |
immed | boolean | true if immediate function invocations must be wrapped in parens. |
latedef | boolean | true if a variable must be defined (declared and have a value) before you can use it. |
laxbreak | boolean | true if protected line breaks (e.g. after return), which lead so semicolon-insertion, should be allowed. |
loopfunc | boolean | true if it should be allowed to define functions within loops. |
noempty | boolean | true if empty blocks should be forbidden. |
nonew | boolean | true if constructors should not have side effects. |
onecase | boolean | true if one case switch statements should be allowed. |
regexdash | boolean | true if an unescaped last dash (-) inside brackets should be permitted in regular expressions. |
regexp | boolean | true if the . should not be allowed in regular expression literals. It tends to match too many characters. |
undef | boolean | true if variables should be declared before use. |
scripturl | boolean | true if javascript: URLs are allowed (JSHint finds them in string literals). |
shadow | boolean | true if variable shadowing should be tolerated. |
supernew | boolean | true if new function () { ... }; and new Object; should be tolerated. |
validthis | boolean | true if this inside a non-constructor function is valid. This is a function scoped option only. |
Related reading
- JSHint homepage
- node-jshint on GitHub
- JavaScript’s JSON API
- Automatic semicolon insertion in JavaScript