JSLINT

The JavaScript Verifier

©2001 Douglas Crockford

jslint is a JavaScript program that looks for problems in JavaScript programs.

What is jslint?

When C was a young programming language, there were several common programming errors that were not caught by the primitive compilers, so an accessory program called lint was developed which would scan a source file, looking for problems.

As the language matured, the definition of the language was strengthened to eliminate some insecurities, and compilers got better at issuing warnings. lint is no longer needed.

JavaScript is a young language. It was originally intended to do small tasks in webpages, tasks for which Java was too heavy and clumsy. But JavaScript is a very capable language, and it is now being used in larger projects. Many of the features that were intended to make the language easy to use are troublesome for larger projects. A lint for JavaScript is needed: jslint.

jslint takes a JavaScript source and scans it. If it finds a problem, it returns a message describing the problem and an approximate location within the source. The problem is not necessarily an error, although it often is. jslint looks at some style conventions as well as structural problems. It does not prove that your program is correct. It just provides another set of eyes to help spot problems.

jslint defines a professional subset of JavaScript.

Semicolon

JavaScript uses a C-like syntax which requires the use of semicolons to delimit statements. JavaScript attempts to make semicolons optional with a semicolon insertion mechanism. This is dangerous.

Like C, JavaScript has ++ and -- operators which can be prefixes or suffixes, and a ( operator which can be a prefix or infix operator. The disambiguation is done by the semicolon.

In Javascript, a linefeed can be whitespace or it can act as a semicolon. This replaces one ambiguity with another.

jslint expects that every statement be followed by ; or } . It will give a warning if that is not the case.

Comma

The comma operator can lead to excessively tricky expressions. It can also mask some programming errors.

jslint expects to see the comma used as a separator, but not as an operator. It does not expect to see elided elements in array literals. Extra commas should not be used.

Line-Ending Punctuators

As a further defense against the semicolon insertion mechanism, jslint expects the last token on a line (ignoring whitespace and comments) to be one of these punctuation characters or prefix operators or infix operators:

, . ; : ? ! ~ { } ( [ + - * % | ^ & = < > += -= *= /= %= &= |=' ^= || && >>> << >> == >>>= <<= >>= != <= >= === !==

jslint does not expect to see an identifier, a string, a number, or a suffix operator at the end of a line:

) ] ++ --

jslint allows you to turn this test off.

Required Blocks

jslint expects that if and for statements will be made with blocks {that is, with statements enclosed in braces}.

JavaScript allows an if to be written like this:

if (condition) statement

That form has been known to contribute to mistakes in projects where many programmers are working on the same code. That is why jslint expects the use of a block:

if (condition) {statement}

Experience shows that this form is more resilient.

Forbidden Blocks

In many languages, a block introduces a scope. Variables introduced in a scope are not visible to other parts of the program.

In JavaScript, blocks do not introduce a scope. There is only function-scope. JavaScript's blocks confuse experienced programmers and lead to errors.

jslint expects blocks with function, if, switch, while, for, do, and try statements and nowhere else.

Expression Statements

An expression statement is expected to be an assignment or a procedure call.

Var

JavaScript allows var definitions to occur anywhere within a function. jslint is more strict.

jslint expects that a var will be declared only once, and that it will be declared before it is used.

jslint expects that parameters will not be declared as vars. Not only is this bad form, it causes Netscape 4 to crash.

jslint does not expect arguments to be declared as a var.

With

The with statement was intended to provide a shorthand in accessing members in deeply nested objects. Unfortunately, it behaves very badly when setting new members. Never use the with statement. Use a var instead.

jslint does not expect to see a with statement.

=

jslint does not expect to see an assignment statement in the control part of an if or while statement. This is because it is more likely that

if (a = b) {...}

was intended to be

if (a == b) {...}

If you really intend an assignment, wrap it in another set of parens:

if ((a = b)) {...}

Labels

JavaScript allows any statement to have a label, and labels have a separate name space. jslint is more strict.

jslint expects labels only on statements that interact with break: switch, while, do, and for. jslint expects that labels will be distinct from vars and parameters.

Unreachable Code

jslint expects that a return, break, continue, or throw statement will be followed by a } or case or default.

Confusing Plusses and Minusses

jslint expects that + will not be followed by + or ++, and that - will not be followed by - or --. Use parens to avoid confusion..

Control Characters in Strings

jslint expects that control characters are not used in literal strings. Use \xhh notation to put control characters in strings.

Void

In most C-like languages, void is a type. In JavaScript, void is a prefix operator that always returns undefined. jslint does not expect to see void because it is confusing and not very useful.

Regular Expressions

jslint does not expect to see whitespace in regular expressions.

Not Looked For

jslint does not look at the use of comments and whitespace. It does not care how you format your code.

It does not do flow analysis to determine that variables are assigned values before used. This is because variables are given a value (undefined), which is a reasonable default for many applications.

It does not do any kind of global analysis. It does not attempt to determine that functions used with new are really constructors, or that method names are spelled correctly.

jslint knows nothing whatsoever about HTML or web browsers. It only knows about Edition 3 of the ECMAScript Language Specification.

Report

If the source is as jslint expects, it generates a function report. It lists for each function:

Feedback

Please let me know if jslint is useful for you. Is it too strict? Is there a check or a report that could speed up your debugging?

I intend to adapt jslint based on your comments. Keep watching for improvements.

Try it

Try it. Paste your script into the window and click the button. The analysis is done by a script running on your machine. Your script is not sent over the network.