-
Notifications
You must be signed in to change notification settings - Fork 6
JavaScript Coding Conventions
This wiki will document recommendations for coding styles and design patterns. All code contributed should try to adhere to these conventions. If there is a convention that doesn't make sense, please file an issue to track it and send email to [email protected].
ClassNames and Enums are TitleCased.
Class.methods, functionNames, and variableNames are camelCased.
CONSTANTS_ARE_UPPERCASED with underscores delimiting words.
FileNames follow ClassName guidelines (TitleCased.)
Examples:
var MY_CONSTANT = 1;
function MyClass() {}
MyClass.prototype = {
method1: function() {
var myVariable = MY_CONSTANT;
...
}
};
function helperThing() {
}
Use underscore prefixes for method names, where the method is intended for private use only. JavaScript does not have access modifier support. TypeScript helps with this, but the access modifiers are not exposed in the produced JavaScript and as such there is still value in differentiating the method names as a way of indicating intent.
Example:
MyClass.prototype.publicMethod = function() { ... }
MyClass.prototype._privateMethod = function() { ... }
It's also worth mentioning that exposing private methods on the prototype is preferred over private functions. This makes the code easily testable and mockable without depending on more complicated solutions to rewire private functionality. There are some cases where functions make sense, for example a closured function in a setImmediate, but even in those situations you should realize they can't be easily replaced and testability should be considered in the design up front.
Use 4 spaces for each indentation level; do not use tabs. When a statement won’t fit on a single line, break it after a comma, an opening paren/brace/bracket, or a binary operator, and indent one level (or two when that makes things clearer). Do not align function arguments with the opening paren of a function call – add a line break before the first argument and indent all arguments one or two levels relative to the previous line. Align the closing paren with the function expression.
Use K&R style, putting opening braces at the ends of lines, rather than on their own lines (this is to avoid problems caused by automatic semicolon insertion, which should never be relied upon). When beginning a line with a closing parenthesis, bracket or brace, align it with the start of the line on which the corresponding opening paren/bracket/brace appears. Put an else on the same line as the preceding closing brace. Always put braces around a control statement body. Don’t introduce blocks that aren’t function bodies or the bodies of control statements (since these really don’t accomplish anything in JavaScript).
Good:
if (...) {
...
} else if (...) {
...
} else {
...
}
longExpression.functionWithLongName(
x,
foo(
anotherLongExpression,
andAnother
),
bar(y, z),
1 + (function () {
...
}())
);
Bad:
if (...)
{
...
}
else if (...)
{
...
}
else
{
...
}
With the exception of ‘.’, put spaces around all binary operators (and the ternary '? :' operator). Do not separate a unary operator from its operand with a space. Always put a space after a keyword. In an object literal, put a space after, but not before, a colon following a property name (and always begin the property value on the same line, after the space).
Do not put a space between a function’s name and the opening paren of its parameter list, whether in a function definition or a function call. Similarly, do not put a space between an array expression and an opening square bracket. Never put spaces immediately inside parentheses or brackets, or before commas, but do always put spaces after commas. When putting an object literal on a single line, do put spaces immediately inside the braces.
Do not put more than one blank line in a row, or begin a function body with a blank line, unless that function is serving as a namespace. Always separate case blocks in switch statements with blank lines.
Good:
while (x < 5)
function foo(x, y, z) {
function (x, y, z) {
{ frotz: 5, frunk: 6 }
frobnicate({
frotz: 5,
frunk: 6
});
foo(1, 2, 3);
bar[i]
Bad:
while(x<5)
function foo ( x, y, z ) {
function( x , y , z ) {
{frotz : 5, frunk : 6}
frobnicate( {
frotz:
5,
frunk:
6
} );
foo (1,2,3);
bar [i]
Use double quotes for all string literals, unless the string needs to contain double quotes. If quoting HTML, use single quotes for attributes inside. Do not use multi-line string literals. The reasoning is that if you make truely serializable JSON blob, it must have double quotes, not single, around property names.
Good:
"Double quotes"
"<div id='foo' />"
Bad:
var foo = 'Single quotes';
Do not use quotes around property names in object literals, unless they are necessary (e.g. the property name contains spaces, or you are creating a strict JSON response that should be parsable). Note that in IE9, quotes are not necessary around JavaScript keywords.
Good:
foo({
count: 5,
description: "Sarcophagi",
"<<$$$>>": "TBD"
});
Bad:
foo({
"count": 5,
"description": "Sarcophagi"
});
Comment your code enough to allow clients to use it and your successors to maintain it easily. Avoid writing the obvious. Use proper capitalization and punctuation at all times, with the sole exception that you usually do not need to add a period at the end of a single-line, single-sentence comment. For function, object or module header comments, prefer the present indicative mood (“Does such-and-such”). For comments within a function, prefer the imperative mood (“Do such-and-such”).
Use “/* */” comments only for comments in the midst of expressions. If you have not set up a preprocessing step in your build, you may wish to avoid them entirely so you have the option of temporarily disabling a block of code. Use C++-style (“//”) comments everywhere else, either on their own lines or to the right of some items (e.g. arguments of a method call). Try to align the latter with each other.
Preserve screen real estate by avoiding comment artwork. Use lines containing just “//” to separate paragraphs in long comments, but do not begin or end comments with such lines. Do put a blank (i.e. whitespace only) line before all comments that are on their own lines. Put a blank line after such comments if they apply to several lines of code that are separated by one or more blank lines.
It is acceptable to follow a closing brace (on its own line) with a short comment identifying the class or function being terminated, but do this sparingly.
Good:
doThings(
param1, // Param1 came from the previous request
param2);
x++; // Everything should now be drawn one pixel further to the right
// Calculates a the layout before handing rendering the viewport. Throws if a cycle is detected.
DetermineLayout(x > maxWidth /* enableWordWrap */);
Bad:
x++; // Increments x
/***************************\
* Clone the given property. *
* Throw if a cycle is *
* detected. *
\***************************/
//
// clone the given property. throw if a cycle is detected.
//
In JavaScript it is a common pattern for a function to accept a single object parameter, the properties of which serve as the actual function parameters. This pattern works well for optional parameters, and also clearly documents what parameters are being passed at the call site. The downsides are the performance cost, slightly more verbose calls, and lack of Intellisense prompting in Visual Studio.
Prefer this pattern for optional parameters, but not required parameters. By convention, name the object parameter options, and make it the last parameter. Do not mutate this parameter in the function body. At the call site, prefer an anonymous object literal, i.e. do not store the object parameter in a variable unless there is a reason to do so.
Consider extracting the true parameters into locals at the start of the function body; this will clarify what the optional parameters are to anyone inspecting the function definition. If the options parameter is itself optional, prefer this pattern, i.e.:
var foo;
var bar;
if (options) {
foo = options.foo;
bar = options.bar;
}
Position vars close to the point of usage, for clarity. However, use caution – in JavaScript vars are visible throughout the function in which they are declared. Write your code as if JavaScript’s vars had the same visibility that they do in C++ and C#. Declaring two variables with the same name in separate blocks of the same function will be flagged by JSLint, and for good reasons. In that case, use slightly different names for the two variables.
In cases where a variable will be assigned different values over time, but the variable has the same meaning in each case (including, among other things, the same expected type), feel free to place the variable in a higher scope and re-use it; there is, after all, a performance benefit from doing so. The code should be structured to make it very clear that the variable is being re-used, so that the value from an earlier part of a function isn’t accidentally read in a later part of the function.
Good:
function foo() {
var bar;
...bar... // Several lines of code that refer to bar
if (...) {
var vaxious1 = ...;
...bar...vaxious1...
}
var merdle = ...;
...bar...merdle...
for (var puggle = ...; ...; ...) {
var vaxious2 = ...;
...bar...merdle...puggle...vaxious2...
}
...bar...merdle...
}
Bad:
function foo() {
var bar,
merdle;
...bar...
if (...) {
var vaxious = ...;
...bar...merdle...vaxious...puggle...
}
merdle = ...;
...bar...merdle...vaxious...puggle...
for (var puggle = ...; ...; ...) {
var vaxious = ...;
...bar...merdle...puggle...vaxious...
}
...bar...merdle...vaxious...puggle...
}
Define each variable on its own line with it's own var statement. Let the minifier optimize the variable declarations. This is primarily to avoid global definitions in the case a semicolon were missed, but helps with readability to enforce we're declaring a variable.
Group variable definitions together. After your block of variable declarations, include a blank line to separate logic execution from variable declaration. This helps promote variable grouping and distinguishes the logic from declarations.
Good:
var someVar;
var somethingElse = ...;
someVar = somethingElse;
Bad:
var someVar,
someRelatedVar = ...;
someVar = someRelatedVar;
If a local function in a method needs access to the current object, using "this" will refer to the window object (or the process object in web workers.) Follow the common convention of a local variable (on its own line) named "_this":
var _this = this;
It is recommended to always put this as the first variable within the outer function scope. That way, future references to "this" within that scope can and should use it. The minifier will crunch down "_this" to "a", which is shorter than "this".
Do not use unnecessary parentheses except when they improve the clarity of the code. In particular, do not parenthesize the operands of unary operators such as new and typeof.
Consider using extra parentheses in the following circumstances:
- To make the relative precedence of similar operators clear
- Around non-trivial expressions on the right hand side of an assignment statement
- Around “? :” expressions
- Around returned expressions that contain parentheses for some other reason
Good:
if (x === 5 || y === 0)
if (x === 5 || (y === 0 && z === 1))
var x = (y !== 1);
return (x > 0 ? x : 0);
return x + y;
return ((x + y) * z);
typeof foo
Bad:
if ((x === 5) || (y === 0))
if (x === 5 || y === 0 && z === 1)
var x = y !== 1;
return x > 0 ? x : 0;
return (x + y);
return (x + y) * z;
typeof(foo)
When calling an anonymous function in a statement context, it is necessary to enclose the function in parentheses. Put the function’s arguments outside these parentheses.
Good:
(function (x) {
...x...
})(y);
Bad:
(function (x) {
...x...
}(y));
Factor common subexpressions into temporary vars. This helps with minification as anything to the right of a period will not be reduced.
Good:
var baz = foo.bar.baz;
if (baz) {
baz.thing();
baz.otherThing();
}
Bad:
if (foo.bar.baz) {
foo.bar.baz.thing();
foo.bar.baz.otherThing();
}
Avoid use of == and !=. Instead use === and !==, unless you actually expect to compare a "truthy" result.
When comparing a variable or expression with a literal (or a variable that is expected to remain constant), put the latter on the right hand side of the comparison operator.
For Booleans, avoid giving false, null and undefined distinct meanings, and do not compare for equality with true or false. For all other types, avoid giving null and undefined distinct meanings, and avoid comparing with undefined and/or null explicitly.
To test whether an object is defined (i.e. not null or undefined), test it as if it were a Boolean. In contrast, do not use string or number expressions in Boolean contexts. Instead, if it is possible that the expression might be null or undefined, test its type. When NaN is a possible value, isNaN can test for either NaN or undefined, but not null. It is therefore best not to let NaN values propagate.
If you must validate if something is explicitly undefined and not just null, use (prop === undefined) to check.
Good:
if (n === 5)
if (myObject)
if (!myObject)
while (!someBool)
if (typeof n === "number" && n !== 0)
if (n !== 0) // If n is known to be defined
if (isNaN(n) || n === null)
Bad:
if (n == 5)
if (5 === n)
if (myObject === null)
if (someBool === true)
while (someBool !== true)
while (someBool === false)
if (n && n !== 5)
Never pass undefined to a function explicitly – use null instead. It is acceptable to omit trailing optional parameters, in which case their values will be undefined. Local variables can be left undefined when they are declared, but remember that it might be necessary to clear them (tonull) in a loop. Do not initialize local variables to null, except inside loops.
Always use the delete operator to remove a property; an assignment to undefined will leave the property with a value of undefined, which is semantically slightly different, and should be avoided.
Functions should either always (implicitly) return undefined (i.e. behave like “void” functions in C) or always return something other than undefined, i.e. don’t use undefined as a valid return value from a non-void function. Functions that return Booleans should always return a valid value, i.e. should never return null.
Good:
var n;
frotz(null, null, 8);
delete foo.bar;
return; // Only if "void" function
Bad:
var n = undefined;
frotz(undefined, undefined, 8);
foo.bar = undefined;
return undefined;
For values that are semantically similar to C or C# enums (i.e. groups of names that map to distinct values, the actual values being of no importance), use an object to serve as the enum type and a property for each named value. This enables Intellisense to list all valid enum values. Use camelCased property names, as usual, but use PascalCase for the enum name, whether it is a var or property. There should be no need for a “nil” or “undefined” enum member – use JavaScript’s null/undefined instead.
Prefer string values with the same names as their properties. This makes it easier to recognize values when debugging, and at an API surface gives clients the option of simply passing string literals. Parameters can be validated by testing EnumName[parameter]. If it is useful to compare against ranges of members (e.g. Color.veryDarkGreen <= color && color <= Color.veryLightGreen), use integer values. If the members must have specific values, or are powers of 2 meant to serve as flags, then the values are of importance and these are “constants” - see the next section.
For example:
var Orientation = {
horizontal: "horizontal",
vertical: "vertical"
};
In general, try to avoid the use of anonymous literals; give them names instead by storing them in “constant” variables or properties. Group related constants (of any type) by making them properties on objects, as in the enum pattern.
Good:
var KEYCODE_LEFT_ARROW = 37;
processKeystroke(KEYCODE_LEFT_ARROW);
Bad:
processKeystroke(37 /* Left arrow */);
To build a long string out of smaller strings, use the += or + operators as needed. These perform at least as well as Array.join, so there is no need to use that (unless you happen to want to concatenate an array of strings).
Feel free to use the ++ and -- operators, either the prefix or postfix variants as appropriate. Use postfix when the two variants would have the same semantics. Be cautious when using them in the middle of statements or expressions, but common patterns where the usage is well-known are fine. If the variable to be incremented/decremented is used in multiple statements, it is better to increment/decrement it on a separate line for clarity.
Good:
foo(x);
bar(x);
x--;
Bad:
foo(x);
bar(x--);
To enumerate through an array, use for loops. Do NOT use forEach functions, as they are a LOT slower. It is also good practice to cache your length in variable to optimize performance of avoiding a length calculation, but be careful doing so. If you are changing the length within the loop, this can lead to a bug.
Good:
var fooLength = foo.length;
for (var i = 0; i < fooLength; i++) { ... }
Bad:
foo.forEach(function (foo, i) { ... });
var fooLength = foo.length;
for (var i = 0; i < fooLength; i++) {
foo.splice(i, 1);
i--;
}
If there are nested loops, avoid using i/j/k naming conventions and use more readable names, like "fooIndex".