These are style guides that I like:
Additionally, there are two style guides that go meta:
This section will cover some general code writing tips.
var statements
The second rule is that, if you are joining an existing project, you should follow its rules rigorously (even if you don’t agree with them).
For most code, the time used for reading it is much greater than the time used for writing it. It is thus important to make the former as easy as possible. Here are some guidelines for doing that:
redBalloon is easier to read than rdBlln.
Most code bases are filled with new ideas and concepts. That means that if you want to work with a code base, you need to learn those ideas and concepts. In contrast to textbooks, the added challenge with code is that people will not read it linearly. They will jump in anywhere and should be able to roughly understand what is going on. Three parts of a code base help:
Much cleverness is directed at these optimizations. However, you normally don’t need them. On one hand, JavaScript engines are becoming increasingly smart and automatically optimize the speed of code that follows established patterns. On the other hand, minification tools (Chapter 32) rewrite your code so that it is as small as possible. In both cases, tools are clever for you, so that you don’t have to be.
Sometimes you have no choice but to optimize the performance of your code. If you do, be sure to measure and optimize the right pieces. In browsers, the problems are often related to DOM and HTML and not the language proper.
A majority of JavaScript programmers agree on the following best practices:
Always use strict equality (===) and strict inequality (!==). I recommend never deviating from this rule. I even prefer the first of the following two conditions, even though they are equivalent:
if(x!==undefined&&x!==null)...// my choiceif(x!=null)...// equivalent
In languages where braces delimit blocks of code, a brace style determines where you put those braces. Two brace styles are most common in C-like languages (such as Java and JavaScript): Allman style and 1TBS.
// Allman brace stylefunctionfoo(x,y,z){if(x){a();}else{b();c();}}
// One True Brace Stylefunctionfoo(x,y,z){if(x){a();}else{b();c();}}
1TBS is a variant of the (older) K&R (Kernighan and Ritchie) style.[21] In K&R style, functions are written in Allman style and braces are omitted where they are not necessary—for example, around single-statement then cases:
// K&R brace stylefunctionfoo(x,y,z){if(x)a();else{b();c();}}
The de facto standard in the JavaScript world is 1TBS. It has been inherited from Java and most style guides recommend it. One reason for that is objective. If you return an object literal, you must put the opening brace in the same line as the keyword return, like this (otherwise, automatic semicolon insertion inserts a semicolon after return, meaning that nothing is returned; see Pitfall: ASI can unexpectedly break up statements):
return{name:'Jane'};
Obviously, an object literal is not a code block, but things look more consistent and you are less likely to make mistakes if both are formatted the same way.
My personal style and preference is:
As an exception, I omit braces if a statement can be written in a single line. For example:
if(x)returnx;
Several constructors produce objects that can also be created by literals. The latter is normally the better choice:
varobj=newObject();// novarobj={};// yesvararr=newArray();// novararr=[];// yesvarregex=newRegExp('abc');// avoid if possiblevarregex=/abc/;// yes
Don’t ever use the constructor Array to create an array with given elements. Initializing an array with elements (avoid!) explains why:
vararr=newArray('a','b','c');// never evervararr=['a','b','c'];// yes
This section collects examples of unrecommended cleverness.
Don’t nest the conditional operator:
// Don’t:returnx===0?'red':x===1?'green':'blue';// Better:if(x===0){return'red';}elseif(x===1){return'green';}else{return'blue';}// Best:switch(x){case0:return'red';case1:return'green';default:return'blue';}
Don’t abbreviate if statements via logical operators:
foo&&bar();// noif(foo)bar();// yesfoo||bar();// noif(!foo)bar();// yes
If possible, use the increment operator (++) and the decrement operator (--) as statements; don’t use them as expressions. In the latter case, they return a value and while there is a mnemonic, you still need to think to figure out what is going on:
// Unsure: what is happening?return++foo;// Easy to understand++foo;returnfoo;
if(x===void0)x=0;// not necessary in ES5if(x===undefined)x=0;// preferable
Starting with ECMAScript 5, the second way of checking is better. Changing undefined explains why.
returnx>>0;// noreturnMath.round(x);// yes
The shift operator can be used to convert a number to an integer. However, it is usually better to use a more explicit alternative such as Math.round(). Converting to Integer gives an overview of all ways of converting to integer.
Sometimes you can be clever in JavaScript—if the cleverness has become an established pattern.
Using the Or (||) operator to provide default values is a common pattern—for example, for parameters:
functionf(x){x=x||0;...}
For details and more examples, consult Pattern: providing a default value.
If you use methods generically, you can abbreviate Object.prototype as {}. The following two expressions are equivalent:
Object.prototype.hasOwnProperty.call(obj,propKey){}.hasOwnProperty.call(obj,propKey)
And Array.prototype can be abbreviated as []:
Array.prototype.slice.call(arguments)[].slice.call(arguments)
I’m ambivalent about this one. It is a hack (you are accessing a prototype property via an instance). But it reduces clutter, and I expect engines to eventually optimize this pattern.
Trailing commas in object literals are legal in ECMAScript 5:
varobj={first:'Jane',last:'Doe',// legal: trailing comma};
ECMAScript 5 also allows you to use reserved words (such as new) as property keys:
> var obj = { new: 'abc' };
> obj.new
'abc'Let’s look at some conventions I like that are a bit more controversial.
We’ll start with syntactic conventions:
I like relatively tight whitespace. The model is written English: there are no spaces after an opening parenthesis and before a closing parenthesis. And there are spaces after commas:
varresult=foo('a','b');vararr=[1,2,3];if(flag){...}
For anonymous functions, I follow Douglas Crockford’s rule of having a space after the keyword function. The rationale is that this is what a named function expression looks like if you remove the name:
functionfoo(arg){...}// named function expressionfunction(arg){...}// anonymous function expression
This helps with reading, because it is easier to make out the scope of the operator:
returnresult?result:theDefault;// noreturn(result?result:theDefault);// yes
Next, I’ll cover conventions for variables:
I don’t declare multiple variables with a single declaration:
// novarfoo=3,bar=2,baz;// yesvarfoo=3;varbar=2;varbaz;
The advantages of this approach are that deleting, inserting, and rearranging lines is simpler and the lines are automatically indented correctly.
var declarations are block-scoped. In other words, you can declare a variable in the context in which it is used (inside a loop, inside a then block or an else block, etc.). This kind of local encapsulation makes a code fragment easier to understand in isolation. It is also easier to remove the code fragment or to move it somewhere else.
As an addendum to the previous rule: don’t declare the same variable twice, in two different blocks. For example:
// Don’t do thisif(v){varx=v;}else{varx=10;}doSomethingWith(x);
The preceding code has the same effect and intention as the following code, which is why it should be written that way:
varx;if(v){x=v;}else{x=10;}doSomethingWith(x);
Now we’ll cover conventions relating to object orientation.
I recommend that you:
new when creating an instance.
The main advantages of doing so are:
For constructors, it is important to use strict mode, because it protects you against forgetting the new operator for instantiation. And you should be aware that you can return any object in a constructor. More tips for using constructors are mentioned in Tips for Implementing Constructors.
I find that such a constructor invocation looks cleaner with parentheses:
varfoo=newFoo;// novarfoo=newFoo();// yes
Use parens so that two operators don’t compete with each other—the result is not always what you might expect:
> false && true || true true > false && (true || true) false > (false && true) || true true
instanceof is especially tricky:
> ! {} instanceof Array
false
> (!{}) instanceof Array
false
> !({} instanceof Array)
trueHowever, I find method calls after a constructor unproblematic:
newFoo().bar().baz();// ok(newFoo()).bar().baz();// not necessary
This section collects various tips:
Coerce a value to a type via Boolean, Number, String(), Object() (used as functions—never use those functions as constructors). The rationale is that this convention is more descriptive:
> +'123' // no
123
> Number('123') // yes
123
> ''+true // no
'true'
> String(true) // yes
'true'this as an implicit parameter
// Avoid:functionhandler(){this.logError(...);}// Prefer:functionhandler(context){context.logError(...);}
in and hasOwnProperty (see Iteration and Detection of Properties)
This is more self-explanatory and safer than comparing with undefined or checking for truthiness:
// All properties:if(obj.foo)// noif(obj.foo!==undefined)// noif('foo'inobj)...// yes// Own properties:if(obj.hasOwnProperty('foo'))...// risky for arbitrary objectsif(Object.prototype.hasOwnProperty.call(obj,'foo'))...// safe
Whenever you are considering a style question, ask yourself: what makes my code easier to understand? Resist the temptation to be clever and leave most of the mechanical cleverness to JavaScript engines and minifiers (see Chapter 32).