JavaScript Standard Style
English • Español (Latinoamérica) • Français • Bahasa Indonesia • Italiano (Italian) • 日本語 (Japanese) • 한국어 (Korean) • Português (Brasil) • 简体中文 (Simplified Chinese) • 繁體中文 (Taiwanese Mandarin)
This is a summary of the standard JavaScript rules.
The best way to learn about standard
is to just install it and give it a try on
your code.
Rules
-
Use 2 spaces for indentation.
eslint:
indent
function hello (name) { console.log('hi', name) }
-
Use single quotes for strings except to avoid escaping.
eslint:
quotes
console.log('hello there') // ✓ ok console.log("hello there") // ✗ avoid console.log(`hello there`) // ✗ avoid $("<div class='box'>") // ✓ ok console.log(`hello ${name}`) // ✓ ok
-
No unused variables.
eslint:
no-unused-vars
function myFunction () { var result = something() // ✗ avoid }
-
Add a space after keywords.
eslint:
keyword-spacing
if (condition) { ... } // ✓ ok if(condition) { ... } // ✗ avoid
-
Add a space before a function declaration's parentheses.
eslint:
space-before-function-paren
function name (arg) { ... } // ✓ ok function name(arg) { ... } // ✗ avoid run(function () { ... }) // ✓ ok run(function() { ... }) // ✗ avoid
-
Always use
===
instead of==
.
Exception:obj == null
is allowed to check fornull || undefined
.eslint:
eqeqeq
if (name === 'John') // ✓ ok if (name == 'John') // ✗ avoid
if (name !== 'John') // ✓ ok if (name != 'John') // ✗ avoid
-
Infix operators must be spaced.
eslint:
space-infix-ops
// ✓ ok var x = 2 var message = 'hello, ' + name + '!'
// ✗ avoid var x=2 var message = 'hello, '+name+'!'
-
Commas should have a space after them.
eslint:
comma-spacing
// ✓ ok var list = [1, 2, 3, 4] function greet (name, options) { ... }
// ✗ avoid var list = [1,2,3,4] function greet (name,options) { ... }
-
Keep else statements on the same line as their curly braces.
eslint:
brace-style
// ✓ ok if (condition) { // ... } else { // ... }
// ✗ avoid if (condition) { // ... } else { // ... }
-
For multi-line if statements, use curly braces.
eslint:
curly
// ✓ ok if (options.quiet !== true) console.log('done')
// ✓ ok if (options.quiet !== true) { console.log('done') }
// ✗ avoid if (options.quiet !== true) console.log('done')
-
Always handle the
err
function parameter.eslint:
handle-callback-err
// ✓ ok run(function (err) { if (err) throw err window.alert('done') })
// ✗ avoid run(function (err) { window.alert('done') })
-
Declare browser globals with a
/* global */
comment.
Exceptions are:window
,document
, andnavigator
.
Prevents accidental use of poorly-named browser globals likeopen
,length
,event
, andname
./* global alert, prompt */ alert('hi') prompt('ok?')
Explicitly referencing the function or property on
window
is okay too, though such code will not run in a Worker which usesself
instead ofwindow
.eslint:
no-undef
window.alert('hi') // ✓ ok
-
Multiple blank lines not allowed.
eslint:
no-multiple-empty-lines
// ✓ ok var value = 'hello world' console.log(value)
// ✗ avoid var value = 'hello world' // blank line // blank line console.log(value)
-
For the ternary operator in a multi-line setting, place
?
and:
on their own lines.eslint:
operator-linebreak
// ✓ ok var location = env.development ? 'localhost' : 'www.api.com' // ✓ ok var location = env.development ? 'localhost' : 'www.api.com' // ✗ avoid var location = env.development ? 'localhost' : 'www.api.com'
-
For var declarations, write each declaration in its own statement.
eslint:
one-var
// ✓ ok var silent = true var verbose = true // ✗ avoid var silent = true, verbose = true // ✗ avoid var silent = true, verbose = true
-
Wrap conditional assignments with additional parentheses. This makes it clear that the expression is intentionally an assignment (
=
) rather than a typo for equality (===
).eslint:
no-cond-assign
// ✓ ok while ((m = text.match(expr))) { // ... } // ✗ avoid while (m = text.match(expr)) { // ... }
-
Add spaces inside single line blocks.
eslint:
block-spacing
function foo () {return true} // ✗ avoid function foo () { return true } // ✓ ok
-
Use camelcase when naming variables and functions.
eslint:
camelcase
function my_function () { } // ✗ avoid function myFunction () { } // ✓ ok var my_var = 'hello' // ✗ avoid var myVar = 'hello' // ✓ ok
-
Trailing commas not allowed.
eslint:
comma-dangle
var obj = { message: 'hello', // ✗ avoid }
-
Commas must be placed at the end of the current line.
eslint:
comma-style
var obj = { foo: 'foo' ,bar: 'bar' // ✗ avoid } var obj = { foo: 'foo', bar: 'bar' // ✓ ok }
-
Dot should be on the same line as property.
eslint:
dot-location
console. log('hello') // ✗ avoid console .log('hello') // ✓ ok
-
Files must end with a newline.
eslint:
eol-last
-
No space between function identifiers and their invocations.
eslint:
func-call-spacing
console.log ('hello') // ✗ avoid console.log('hello') // ✓ ok
-
Add space between colon and value in key value pairs.
eslint:
key-spacing
var obj = { 'key' : 'value' } // ✗ avoid var obj = { 'key' :'value' } // ✗ avoid var obj = { 'key':'value' } // ✗ avoid var obj = { 'key': 'value' } // ✓ ok
-
Constructor names must begin with a capital letter.
eslint:
new-cap
function animal () {} var dog = new animal() // ✗ avoid function Animal () {} var dog = new Animal() // ✓ ok
-
Constructor with no arguments must be invoked with parentheses.
eslint:
new-parens
function Animal () {} var dog = new Animal // ✗ avoid var dog = new Animal() // ✓ ok
-
Objects must contain a getter when a setter is defined.
eslint:
accessor-pairs
var person = { set name (value) { // ✗ avoid this._name = value } } var person = { set name (value) { this._name = value }, get name () { // ✓ ok return this._name } }
-
Constructors of derived classes must call
super
.eslint:
constructor-super
class Dog { constructor () { super() // ✗ avoid this.legs = 4 } } class Dog extends Animal { constructor () { // ✗ avoid this.legs = 4 } } class Dog extends Animal { constructor () { super() // ✓ ok this.legs = 4 } }
-
Use array literals instead of array constructors.
eslint:
no-array-constructor
var nums = new Array(1, 2, 3) // ✗ avoid var nums = [1, 2, 3] // ✓ ok
-
Avoid using
arguments.callee
andarguments.caller
.eslint:
no-caller
function foo (n) { if (n <= 0) return arguments.callee(n - 1) // ✗ avoid } function foo (n) { if (n <= 0) return foo(n - 1) // ✓ ok }
-
Avoid modifying variables of class declarations.
eslint:
no-class-assign
class Dog {} Dog = 'Fido' // ✗ avoid
-
Avoid modifying variables declared using
const
.eslint:
no-const-assign
const score = 100 score = 125 // ✗ avoid
-
Avoid using constant expressions in conditions (except loops).
eslint:
no-constant-condition
if (false) { // ✗ avoid // ... } if (x === 0) { // ✓ ok // ... } while (true) { // ✓ ok // ... }
-
No control characters in regular expressions.
eslint:
no-control-regex
var pattern = /\x1f/ // ✗ avoid var pattern = /\x20/ // ✓ ok
-
No
debugger
statements.eslint:
no-debugger
function sum (a, b) { debugger // ✗ avoid return a + b }
-
No
delete
operator on variables.eslint:
no-delete-var
var name delete name // ✗ avoid
-
No duplicate arguments in function definitions.
eslint:
no-dupe-args
function sum (a, b, a) { // ✗ avoid // ... } function sum (a, b, c) { // ✓ ok // ... }
-
No duplicate name in class members.
eslint:
no-dupe-class-members
class Dog { bark () {} bark () {} // ✗ avoid }
-
No duplicate keys in object literals.
eslint:
no-dupe-keys
var user = { name: 'Jane Doe', name: 'John Doe' // ✗ avoid }
-
No duplicate
case
labels inswitch
statements.eslint:
no-duplicate-case
switch (id) { case 1: // ... case 1: // ✗ avoid }
-
Use a single import statement per module.
eslint:
no-duplicate-imports
import { myFunc1 } from 'module' import { myFunc2 } from 'module' // ✗ avoid import { myFunc1, myFunc2 } from 'module' // ✓ ok
-
No empty character classes in regular expressions.
eslint:
no-empty-character-class
const myRegex = /^abc[]/ // ✗ avoid const myRegex = /^abc[a-z]/ // ✓ ok
-
No empty destructuring patterns.
eslint:
no-empty-pattern
const { a: {} } = foo // ✗ avoid const { a: { b } } = foo // ✓ ok
-
No using
eval()
.eslint:
no-eval
eval( "var result = user." + propName ) // ✗ avoid var result = user[propName] // ✓ ok
-
No reassigning exceptions in
catch
clauses.eslint:
no-ex-assign
try { // ... } catch (e) { e = 'new value' // ✗ avoid } try { // ... } catch (e) { const newVal = 'new value' // ✓ ok }
-
No extending native objects.
eslint:
no-extend-native
Object.prototype.age = 21 // ✗ avoid
-
Avoid unnecessary function binding.
eslint:
no-extra-bind
const name = function () { getName() }.bind(user) // ✗ avoid const name = function () { this.getName() }.bind(user) // ✓ ok
-
Avoid unnecessary boolean casts.
eslint:
no-extra-boolean-cast
const result = true if (!!result) { // ✗ avoid // ... } const result = true if (result) { // ✓ ok // ... }
-
No unnecessary parentheses around function expressions.
eslint:
no-extra-parens
const myFunc = (function () { }) // ✗ avoid const myFunc = function () { } // ✓ ok
-
Use
break
to prevent fallthrough inswitch
cases.eslint:
no-fallthrough
switch (filter) { case 1: doSomething() // ✗ avoid case 2: doSomethingElse() } switch (filter) { case 1: doSomething() break // ✓ ok case 2: doSomethingElse() } switch (filter) { case 1: doSomething() // fallthrough // ✓ ok case 2: doSomethingElse() }
-
No floating decimals.
eslint:
no-floating-decimal
const discount = .5 // ✗ avoid const discount = 0.5 // ✓ ok
-
Avoid reassigning function declarations.
eslint:
no-func-assign
function myFunc () { } myFunc = myOtherFunc // ✗ avoid
-
No reassigning read-only global variables.
eslint:
no-global-assign
window = {} // ✗ avoid
-
No implied
eval()
.eslint:
no-implied-eval
setTimeout("alert('Hello world')") // ✗ avoid setTimeout(function () { alert('Hello world') }) // ✓ ok
-
No function declarations in nested blocks.
eslint:
no-inner-declarations
if (authenticated) { function setAuthUser () {} // ✗ avoid }
-
No invalid regular expression strings in
RegExp
constructors.eslint:
no-invalid-regexp
RegExp('[a-z') // ✗ avoid RegExp('[a-z]') // ✓ ok
-
No irregular whitespace.
eslint:
no-irregular-whitespace
function myFunc () /*<NBSP>*/{} // ✗ avoid
-
No using
__iterator__
.eslint:
no-iterator
Foo.prototype.__iterator__ = function () {} // ✗ avoid
-
No labels that share a name with an in scope variable.
eslint:
no-label-var
var score = 100 function game () { score: while (true) { // ✗ avoid score -= 10 if (score > 0) continue score break } }
-
No label statements.
eslint:
no-labels
label: while (true) { break label // ✗ avoid }
-
No unnecessary nested blocks.
eslint:
no-lone-blocks
function myFunc () { { // ✗ avoid myOtherFunc() } } function myFunc () { myOtherFunc() // ✓ ok }
-
Avoid mixing spaces and tabs for indentation.
eslint:
no-mixed-spaces-and-tabs
-
Do not use multiple spaces except for indentation.
eslint:
no-multi-spaces
const id = 1234 // ✗ avoid const id = 1234 // ✓ ok
-
No multiline strings.
eslint:
no-multi-str
const message = 'Hello \ world' // ✗ avoid
-
No
new
without assigning object to a variable.eslint:
no-new
new Character() // ✗ avoid const character = new Character() // ✓ ok
-
No using the
Function
constructor.eslint:
no-new-func
var sum = new Function('a', 'b', 'return a + b') // ✗ avoid
-
No using the
Object
constructor.eslint:
no-new-object
let config = new Object() // ✗ avoid
-
No using
new require
.eslint:
no-new-require
const myModule = new require('my-module') // ✗ avoid
-
No using the
Symbol
constructor.eslint:
no-new-symbol
const foo = new Symbol('foo') // ✗ avoid
-
No using primitive wrapper instances.
eslint:
no-new-wrappers
const message = new String('hello') // ✗ avoid
-
No calling global object properties as functions.
eslint:
no-obj-calls
const math = Math() // ✗ avoid
-
No octal literals.
eslint:
no-octal
const octal = 042 // ✗ avoid const decimal = 34 // ✓ ok const octalString = '042' // ✓ ok
-
No octal escape sequences in string literals.
eslint:
no-octal-escape
const copyright = 'Copyright \251' // ✗ avoid
-
Avoid string concatenation when using
__dirname
and__filename
.eslint:
no-path-concat
const pathToFile = __dirname + '/app.js' // ✗ avoid const pathToFile = path.join(__dirname, 'app.js') // ✓ ok
-
Avoid using
__proto__
. UsegetPrototypeOf
instead.eslint:
no-proto
const foo = obj.__proto__ // ✗ avoid const foo = Object.getPrototypeOf(obj) // ✓ ok
-
No redeclaring variables.
eslint:
no-redeclare
let name = 'John' let name = 'Jane' // ✗ avoid let name = 'John' name = 'Jane' // ✓ ok
-
Avoid multiple spaces in regular expression literals.
eslint:
no-regex-spaces
const regexp = /test value/ // ✗ avoid const regexp = /test {3}value/ // ✓ ok const regexp = /test value/ // ✓ ok
-
Assignments in return statements must be surrounded by parentheses.
eslint:
no-return-assign
function sum (a, b) { return result = a + b // ✗ avoid } function sum (a, b) { return (result = a + b) // ✓ ok }
-
Avoid assigning a variable to itself
eslint:
no-self-assign
name = name // ✗ avoid
-
Avoid comparing a variable to itself.
eslint:
no-self-compare
if (score === score) {} // ✗ avoid
-
Avoid using the comma operator.
eslint:
no-sequences
if (doSomething(), !!test) {} // ✗ avoid
-
Restricted names should not be shadowed.
eslint:
no-shadow-restricted-names
let undefined = 'value' // ✗ avoid
-
Sparse arrays are not allowed.
eslint:
no-sparse-arrays
let fruits = ['apple',, 'orange'] // ✗ avoid
-
Tabs should not be used
eslint:
no-tabs
-
Regular strings must not contain template literal placeholders.
eslint:
no-template-curly-in-string
const message = 'Hello ${name}' // ✗ avoid const message = `Hello ${name}` // ✓ ok
-
super()
must be called before usingthis
.eslint:
no-this-before-super
class Dog extends Animal { constructor () { this.legs = 4 // ✗ avoid super() } }
-
Only
throw
anError
object.eslint:
no-throw-literal
throw 'error' // ✗ avoid throw new Error('error') // ✓ ok
-
Whitespace not allowed at end of line.
eslint:
no-trailing-spaces
-
Initializing to
undefined
is not allowed.eslint:
no-undef-init
let name = undefined // ✗ avoid let name name = 'value' // ✓ ok
-
No unmodified conditions of loops.
eslint:
no-unmodified-loop-condition
for (let i = 0; i < items.length; j++) {...} // ✗ avoid for (let i = 0; i < items.length; i++) {...} // ✓ ok
-
No ternary operators when simpler alternatives exist.
eslint:
no-unneeded-ternary
let score = val ? val : 0 // ✗ avoid let score = val || 0 // ✓ ok
-
No unreachable code after
return
,throw
,continue
, andbreak
statements.eslint:
no-unreachable
function doSomething () { return true console.log('never called') // ✗ avoid }
-
No flow control statements in
finally
blocks.eslint:
no-unsafe-finally
try { // ... } catch (e) { // ... } finally { return 42 // ✗ avoid }
-
The left operand of relational operators must not be negated.
eslint:
no-unsafe-negation
if (!key in obj) {} // ✗ avoid if (!(key in obj)) {} // ✓ ok
-
Avoid unnecessary use of
.call()
and.apply()
.eslint:
no-useless-call
sum.call(null, 1, 2, 3) // ✗ avoid
-
Avoid using unnecessary computed property keys on objects.
eslint:
no-useless-computed-key
const user = { ['name']: 'John Doe' } // ✗ avoid const user = { name: 'John Doe' } // ✓ ok
-
No unnecessary constructor.
eslint:
no-useless-constructor
class Car { constructor () { // ✗ avoid } }
-
No unnecessary use of escape.
eslint:
no-useless-escape
let message = 'Hell\o' // ✗ avoid
-
Renaming import, export, and destructured assignments to the same name is not allowed.
eslint:
no-useless-rename
import { config as config } from './config' // ✗ avoid import { config } from './config' // ✓ ok
-
No whitespace before properties.
eslint:
no-whitespace-before-property
user .name // ✗ avoid user.name // ✓ ok
-
No using
with
statements.eslint:
no-with
with (val) {...} // ✗ avoid
-
Maintain consistency of newlines between object properties.
eslint:
object-property-newline
const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' // ✗ avoid } const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' } // ✓ ok const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' } // ✓ ok
-
No padding within blocks.
eslint:
padded-blocks
if (user) { // ✗ avoid const name = getName() } if (user) { const name = getName() // ✓ ok }
-
No whitespace between spread operators and their expressions.
eslint:
rest-spread-spacing
fn(... args) // ✗ avoid fn(...args) // ✓ ok
-
Semicolons must have a space after and no space before.
eslint:
semi-spacing
for (let i = 0 ;i < items.length ;i++) {...} // ✗ avoid for (let i = 0; i < items.length; i++) {...} // ✓ ok
-
Must have a space before blocks.
eslint:
space-before-blocks
if (admin){...} // ✗ avoid if (admin) {...} // ✓ ok
-
No spaces inside parentheses.
eslint:
space-in-parens
getName( name ) // ✗ avoid getName(name) // ✓ ok
-
Unary operators must have a space after.
eslint:
space-unary-ops
typeof!admin // ✗ avoid typeof !admin // ✓ ok
-
Use spaces inside comments.
eslint:
spaced-comment
//comment // ✗ avoid // comment // ✓ ok /*comment*/ // ✗ avoid /* comment */ // ✓ ok
-
No spacing in template strings.
eslint:
template-curly-spacing
const message = `Hello, ${ name }` // ✗ avoid const message = `Hello, ${name}` // ✓ ok
-
Use
isNaN()
when checking forNaN
.eslint:
use-isnan
if (price === NaN) { } // ✗ avoid if (isNaN(price)) { } // ✓ ok
-
typeof
must be compared to a valid string.eslint:
valid-typeof
typeof name === 'undefimed' // ✗ avoid typeof name === 'undefined' // ✓ ok
-
Immediately Invoked Function Expressions (IIFEs) must be wrapped.
eslint:
wrap-iife
const getName = function () { }() // ✗ avoid const getName = (function () { }()) // ✓ ok const getName = (function () { })() // ✓ ok
-
The
*
inyield*
expressions must have a space before and after.eslint:
yield-star-spacing
yield* increment() // ✗ avoid yield * increment() // ✓ ok
-
Avoid Yoda conditions.
eslint:
yoda
if (42 === age) { } // ✗ avoid if (age === 42) { } // ✓ ok
Semicolons
-
eslint:
semi
window.alert('hi') // ✓ ok window.alert('hi'); // ✗ avoid
-
Never start a line with
(
,[
,`
, or a handful of other unlikely possibilities.This is the only gotcha with omitting semicolons, and
standard
protects you from this potential issue.(The full list is:
[
,(
,`
,+
,*
,/
,-
,,
,.
, but most of these will never appear at the start of a line in real code.)eslint:
no-unexpected-multiline
// ✓ ok ;(function () { window.alert('ok') }()) // ✗ avoid (function () { window.alert('ok') }())
// ✓ ok ;[1, 2, 3].forEach(bar) // ✗ avoid [1, 2, 3].forEach(bar)
// ✓ ok ;`hello`.indexOf('o') // ✗ avoid `hello`.indexOf('o')
Note: If you're often writing code like this, you may be trying to be too clever.
Clever short-hands are discouraged, in favor of clear and readable expressions, whenever possible.
Instead of this:
;[1, 2, 3].forEach(bar)
This is strongly preferred:
var nums = [1, 2, 3] nums.forEach(bar)
Helpful reading
- An Open Letter to JavaScript Leaders Regarding Semicolons
- JavaScript Semicolon Insertion – Everything you need to know
And a helpful video:
All popular code minifiers in use today use AST-based minification, so they can handle semicolon-less JavaScript with no issues (since semicolons are not required in JavaScript).
Excerpt from "An Open Letter to JavaScript Leaders Regarding Semicolons":
[Relying on automatic semicolon insertion] is quite safe, and perfectly valid JS that every browser understands. Closure compiler, yuicompressor, packer, and jsmin all can properly minify it. There is no performance impact anywhere.
I am sorry that, instead of educating you, the leaders in this language community have given you lies and fear. That was shameful. I recommend learning how statements in JS are actually terminated (and in which cases they are not terminated), so that you can write code that you find beautiful.
In general,
\n
ends a statement unless: 1. The statement has an unclosed paren, array literal, or object literal or ends in some other way that is not a valid way to end a statement. (For instance, ending with.
or,
.) 2. The line is--
or++
(in which case it will decrement/increment the next token.) 3. It is afor()
,while()
,do
,if()
, orelse
, and there is no{
4. The next line starts with[
,(
,+
,*
,/
,-
,,
,.
, or some other binary operator that can only be found between two tokens in a single expression.The first is pretty obvious. Even JSLint is ok with
\n
chars in JSON and parenthesized constructs, and withvar
statements that span multiple lines ending in,
.The second is super weird. I’ve never seen a case (outside of these sorts of conversations) where you’d want to do write
i\n++\nj
, but, point of fact, that’s parsed asi; ++j
, noti++; j
.The third is well understood, if generally despised.
if (x)\ny()
is equivalent toif (x) { y() }
. The construct doesn’t end until it reaches either a block, or a statement.
;
is a valid JavaScript statement, soif(x);
is equivalent toif(x){}
or, “If x, do nothing.” This is more commonly applied to loops where the loop check also is the update function. Unusual, but not unheard of.The fourth is generally the fud-inducing “oh noes, you need semicolons!” case. But, as it turns out, it’s quite easy to prefix those lines with semicolons if you don’t mean them to be continuations of the previous line. For example, instead of this:
foo(); [1,2,3].forEach(bar);
you could do this:
foo() ;[1,2,3].forEach(bar)
The advantage is that the prefixes are easier to notice, once you are accustomed to never seeing lines starting with
(
or[
without semis.