- Comment, document, and test liberally
- Prefer maintainability over performance
- Write your JavaScript as if it's C, or write it as if it's Lisp, but never as if it's Java as its name implies.
In no particular order:
- No long functions. No hard limit. Rule of thumb: if it performs more than one logical operation, split it up. Best to stay low double digits in terms of line numbers.
- Cache DOM references if they are looked up more than once
- Avoid global states. States in modules and closures are fine (and often necessary).
- Prefer pure functions. Corollary to avoiding global states. Functions which
produce effect as output (e.g.
Math.random
) are fine, just not side-effects (e.g.this.a = this.b + 2
). - Avoid prototypes. Corollary to preferring pure functions. Object-oriented programming is necessary only when programming in an environment without access to closure or a strong type system.
- Use
new
andthis
sparingly. Only usethis
in constructors andnew
for data types (i.e. no methods). - ALWAYS use semicolons. Never rely on automatic semicolon insertion. It will break your mind.
- Always name your function. Static functions are preferred over anonymous
functions, even if you need to do this:
exports.doSomething = function doSomething () {}
. This is for debugging purpose. - NEVER use
arguments
. Engines can't optimize it, nor can you easily reason about a function using it. You should really be using an array instead of variadic parameters. - Avoid
try...catch
. JavaScript already gives sparse and useless error messages. Don't make your life harder by allowing your code to arbitrarily hide them. Plus, JavaScript engines can't optimize any code in thetry...catch
block. If you must use it (e.g.JSON.parse
), isolate it in its own function. - Do not nest anything. This includes
setTimeout
, callbacks, and functions. Having one level of nesting is acceptable but more than that is a sign of something wrong. - No flexible object structure. If you need to do something like
a = b[0].child[4]
, you're doing something wrong. If a complex structure is needed, decompose it with a series of composed/chained functions. - Use data types. Typing is good for your mind. Logical data types like
Person
, not machine types likeint
. - Single assignment. Do not re-use variables for different purposes. There is
no valid use case for that. Note that re-assigning
i
in a loop does not count as it is used for the same purpose.
Prefer pure functions for "logic". Logic is loosely defined here. Essentially most code is logic code. "Non-logic" code would be any direct I/O (e.g. DOM, localStorage, XMLHttpRequest).
References to free variables (i.e. those outside of the currently executing function) other than variables from the same component are prohibited.
Use impure functions for presentation.
- Use Mocha for testing
- Use Google Closure Compiler JSDoc style for documentation
- Prefer using libraries over writing code
- Read JavaScript: The Good Parts
- FIRST, cache all DOM elements that are used more than once.
- Use hand-coded JavaScript. It is much more difficult to optimize with CoffeeScript or other compile-to-JavaScript languages.
- Only use static functions or functions in simple objects (i.e. no prototypes).
- In fact, use pure, static functions, which are the closest thing to inlining code.
- Keep objects and arrays out if possible (i.e. use multiple variables instead an object).
- Prefer native arrays over typed arrays.
- If you must use objects, prefer dot notation.
- Prefer straight function calls (e.g. avoid using event listeners and heavily wrapped functions).
- Avoid closures, at least deeply nested closures.
- Always use
while
loop over any other looping methods. It's much faster while being non-destructive. - Prefer local over closure (and by extension, global) variables. If access to closure variables is a must, cache it as soon as the function begins by declaring a local variable.
- Use
parseInt
on Safari-family engines and- 0
on other major engines. For convenience, always use- 0
. - Use
className
for initialization but useclassList
for subsequent operations. - When a game loop is used, and of course you're using
requestAnimationFrame
, which only takes a function, you should put the parameters as global/closure variables instead of using a closure orbind
. - Use functions liberally as function calls are slower but the difference is negligible. An implication is that using functions to wrap around common nested property lookup operations to save output size is desirable.
- You should never use the
arguments
object.
Basically, use a flat data structure (to avoid object lookup penalty) with as much heap data pre-allocated as possible (to avoid garbage collection), and cache references to closure variables (to avoid the closure lookup penalty).
Note that pure local variables (i.e. those in leaf node functions) live on the stack so the garbage collection issue doesn't apply. Only closure variables live in the heap.