Code style guide
Formatting
Indentation
Each indentation level is made up of one tab. Do not use spaces. This allows each person to customize the size of their tab for their visual needs. Read why we should default to Tabs instead of Spaces for an accessible first environment for more discussion.
if (true) {
doSomething();
}
Statement termination
End all statements with a semi-colon in JS and CSS.
return 'this is a random string';
Line length
Code and documentation line length is no more than 100 columns.
The exception to this is if the code is an HTML injection into the DOM. This code remains condensed in one strong as long as necessary.
el.append('<div class="container"><p>Do you truly intend to
perform this action?</p><button class="btn primary"
type="button">I do</button></div>');
If a line reaches the maximum length, break it on an operator or a chain (a comma or period) for easiest reading. The next line is indented one additional level. Align chained commands.
$.get(url)
.fail(function() {
return false;
})
.done(function() {
return true;
});
For assigning variable values, align the overflow with the column of the first value.
var results = thisIsAVariable + thisIsAnotherVariable +
probablyOneMoreVariable;
Blank lines
Add one blank line in between methods, as well as within methods before flow control statements, and style statements.
//comment
if (statement) {
var el = 0;
if (var === 0) {
return true;
}
}
Quotations
Use single quotes for all variables and related code; use double quotes when writing HTML inside the single quote variables.
var html = '<h1 class=”h1”>Welcome</h1>';
Naming
For JS, variable and function names must be descriptive but kept as short as possible. Use camel-casing for multi-word names. Variable names start with a noun and function names start with a verb. The variable name should indicate the type of variable, e.g. count, length, and size are likely to be integers.
Some verb name starters for functions:
- can-
- function returns a boolean
- Example: canHydrate
- has-
- function returns a boolean
- Example: hasContent
- is-
- function returns a boolean
- Example: isChecked
- get-
- function returns a nonboolean
- Example: getItemList
- set-
- function is used to save a value
- Example: setItemList
Some abbreviated variable names are acceptable such as those used through multiple methods or style statements.
var t = $(this);
var pid = person id;
var rid = request id;
var lid = list id;
var el = event listener;
var d = data object;
Constants
Variables intended to be constant are styled in uppercase with underscores to separate words in the name. Any variable styled as a constant should not change.
if (count < MAX_COUNT) {
doSomething();
}
Constructors
When creating objects, use Pascal camel case and a noun to more clearly differentiate it from functions.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
alert(this.name);
}
var me = new Person('George');
Decimals
Do not leave a decimal point hanging (e.g. 1. or .1 should be 1.0 or 0.1).
Null vs. undefined
var person = null; //null
var person; //undefined
Arrays
Do not explicitly state the constructor when creating an array. Remove spaces between values unless it cannot fit on one line. In that case, the opening bracket remains on the initial declaration line and each value has its own line.
var colors = ['red','yellow','blue'];
var years = [
'1971',
'1983',
'1988',
'1990',
'1995',
'1999',
'2008'
];
Comments and documentation
Use JSDoc for properly documenting javascript functions. Also include single line comment lines to clarify what the code is doing, especially if it could be easily misunderstood. Use single line or multi-line comments to comment out code chunks.
/** @description Alerts the person that an error was found
@fires alertmessage
*/
function alertUser(message) {
//the user id is found in the DOM
var id = getId();
//var otherId = soemthing;
/* if(id === otherId) {
alertmessage();
}
*/
}
Debugging
When working with code in development mode, prefer using console.log()
over alert()
to display data in the browser. For more advanced logging, use console.info()
(informational), console.warn()
(warning), and console.error()
(error that is also counted towards all page errors).
Always comment out or remove all alert and console calls in the code before releasing code to production.
Statements and expressions
Always use brackets and semi colons. Put a space between the function parameters (the parenthetical variables) and the bracket. Put a space between an expression and the conditions, but not within the condition parentheses or within the function parameters.
function hello() {
console.log('Hello.');
}
if (state) {
hello();
}
Switch
Switch statements follow similar bracket styling. Each case is indented, and the code listed on the next line. Cases are not separated by extra breaklines.
The Default
case is required. Add break statement to the end of every case unless falling through (the ability to "or"
cases together. Falling through may only be done if the previous cases do not contain additional code.
switch(action) {
case 'login':
login();
break;
case 'timeout':
case 'logout':
logout();
break;
default:
console.log('No action');
}
With
Do not use With
coding.
For
Use to iterate through an array. use for-in
to iterate through objects.
Variables, operators, and functions
Declaring variables and functions
Declare all variables at the beginning of the function in a single variable initiation call. Combine similar attributes together and order accordingly if a variable is dependent on another.
Functions must be placed above any calls to that function. When nesting a function within a function, place the function right below the variable declarations and before the logic begins. Nested functions cannot be declared inside block statements (e.g. if/else).
function getList() {
var t = $(this),
list = t.closest('ul'),
pid = getId(),
x;
function checkLogin(pid,t) {
return login(pid);
}
if (checkLogin) {
x = list;
}
}
Additionally, a variable may immediate invoke a function to assign a value. Include parentheses around the function.
var pid = function() {
return getId();
}
Equal
Use ==
for comparing values with loose equality (same value but could be different types, e.g. 5 == "5"
will return true), and use ===
for strict equality (value and type must be the same, e.g. 5 === "5"
will return false). Prefer ===
when performing comparisons.
Unary operators
Prefer to use prefix unary operators over postfix (++a
over a++
) to avoid potential issues in code execution order (prefix will increment before being executed when nested inside an executable statement such as alert(++a);
).
Ternary operators
Where possible, write code with ternary operators to reduce code. Syntax is condition ? true : false
.
var highscore = (player1 > player2) ? player1 : player2;
//equivalent to
var highscore;
if (player1 > player2) {
highscore = player1;
else {
highscore = player2;
}
Loosely couple UI layers
Use as much loose coupling between front end layers (HTML, CSS, and JS) as possible so they do not rely heavily on each other (reduces errors when changing code).
Do not mix CSS and JS; JS only exists in JS files and CSS only in CSS files (e.g. do not use CSS expressions and apply classes and not styles in JS).
Do not use JS HTML embedded event handlers, such as onClick
.
When generating HTML from JS, use Handlebars to create the templates to preserve loose coupling.
Avoid globals
Write as much of the data local to the function rather than using globals.
Note: A variable declared locally but missing var
becomes global (e.g. instantiated as title = "Test"
rather than var title = "Test"
). Ensure proper syntax is followed.
When creating HTML templates for javascript, use Handlebars rather than inserting HTML into the JS file.
If global variables cannot be avoided, use the one-global approach with namespaces.
Event handling
Decouple events from application logic; a function should not be defined within an event handler, only called.
When calling a function for an event, only pass the data in the event logic needed for that function (e.g. not event
but event.clientX
as a parameter) and not the entire event object.
The event handler function should also handle the event default actions such as preventDefault()
and stopPropagation()
.
var application() = {
clickEvent: function(e) {
e.preventDefault();
e.stopPropagation();
this.showTip(e.clientX,e.clientY);
},
showTip: function(x,y) {
var tip = $('#tip');
tip.addClass('hasValue');
}
};
addListener(el,'click',function(e) {
application.clickEvent(e);
});
Avoid null comparisons
Use typeof to detect the correct primitive type (string, number, Boolean, null, and undefined). Use null only if null is an expected type (such as determining the existence of an element).
if (tyopeof name === 'string') {}
if (tyopeof count === 'number') {}
if (tyopeof found === 'boolean' && found) {}
if (tyopeof app === 'undefined') {}
For reference values, or objects, use instanceof to determine type, which also includes the prototype chain (e.g. Date type is a child of Object, so test would pass for both). Note: instanceof detection does not work if data is being passed to different frames.
if (value instanceof Date) {/*date object*/}
if (value instanceof RegExp) {/*regular expression object*/}
if (value instanceof Error) {/*error object*/}
To detect functions in browsers not IE8 or older, use typeof.
Arrays may be identified with the isArray()
function, although adding older checks (for browsers using ECMAScript 4 or older) may be valuable.
function isArray(value) {
if (typeof Array.isArray === 'function') {
return Array.isArray(value);
}
else {
return Object.prototype.toString.call(value) === '[object Array]';
}
}
Checking the existence of object properties, use "in" testing. To check a specific instance, hasOwnProperty()
may work if IE8 and earlier is not supported.
var object = {
count: 0,
related: null
}
if ('count' in object) {}
Configuration data
Configuration data consists of any hardcoded values such as URLs, strings returned to the UI (e.g. error messages), repeated unique values (e.g. a class name), settings, and any changeable values.
Create a separate config file to manage all the values and call the references in the code:
config.js
var config = {
'MSG_INVALID_VALUE': 'Invalid value';
'URL_INVALID': '/errors/invalid.html';
};
application.js
var validate(value) {
if (!value) {
alert(config.MSG_INVALID_VALUE);
location.href = config.URL_INVALID;
}
}
Error throwing
Include custom error messages to more easily find erroneous code. Best used in utility functions often used in multiple places.
function getDivs(el) {
if (el && el.getElementsByTagName) {
return el.getElementsByTagName('div');
}
else {
throw new Error ('getDivs(): Argument must be a DOM element.');
}
}
Ordering CSS properties
Organize CSS properties by purpose.
- Box model properties
- Layout properties
- Background properties
- Typographic properties
- Colors and borders
- Effects including animation