This is a guide, not a law - use your discretion. Mostly based on Felix Geisendörfer's guide with our own tweaks.
Use 2 spaces for indenting your code and swear an oath to never mix tabs and spaces - a special kind of hell is awaiting you otherwise.
Use UNIX-style newlines (\n
), and a newline character as the last character
of a file. Windows-style newlines (\r\n
) are forbidden inside any repository.
Just like you brush your teeth after every meal, you clean up any trailing whitespace in your JS files before committing. Otherwise the rotten smell of careless neglect will eventually drive away contributors and/or co-workers.
According to scientific research, the usage of semicolons is a core value of our community. Consider the points of the opposition, but be a traditionalist when it comes to abusing error correction mechanisms for cheap syntactic pleasures.
Use single quotes, unless you are writing JSON.
Right:
const foo = 'bar';
Wrong:
const foo = "bar";
Your opening braces go on the same line as the statement, with whitespace before and after the condition, followed by a new line.
Right:
if (true) {
console.log('winning');
}
Wrong:
if (true)
{
console.log('losing');
}
if (true) { console.log('losing'); }
if(true){
console.log('winning');
}
One method per line should be used if you want to chain methods.
You should also indent these methods so it's easier to tell they are part of the same chain.
Right:
User
.findOne({ name: 'foo' })
.populate('bar')
.exec(() => true);
Wrong:
User
.findOne({ name: 'foo' })
.populate('bar')
.exec(() => true);
User.findOne({ name: 'foo' })
.populate('bar')
.exec(() => true);
User.findOne({ name: 'foo' }).populate('bar')
.exec(() => true);
User.findOne({ name: 'foo' }).populate('bar')
.exec(() => true);
Variables, properties and function names should use lowerCamelCase
. They
should also be descriptive. Single character variables and uncommon
abbreviations should generally be avoided.
Right:
const adminUser = db.query();
Wrong:
const admin_user = db.query();
Class names should be capitalized using UpperCamelCase
.
Right:
function BankAccount() {
}
Wrong:
function bank_Account() {
}
All property names in CouchDB documents use lowercase underscore-separated formatting.
Right:
{
"word": "values can have spaces and CAPS",
"multiple_words": true
}
Wrong:
{
"UPPER_CASE_NAME": false,
"lowercasename": false,
"camelCaseName": false,
"kebab-case-name": false,
"Title_case_name": false,
"sTuDlYcAsEnAmE": false
}
There is no longer a good reason to use var
. Use const
whenever you can,
and let
when you must. Hardcoded constants should be named in all UPPERCASE.
Right:
const DELAY = 10 * 1000;
const output = input * 10;
let temp = 50;
let unknown;
Wrong:
var DELAY = 10 * 1000;
Use arrow functions as much as possible for cleaner code and better scoping. Omit the return keyword when the entire function definition fits on one line. Omit the parens when taking a single parameter.
There are exceptions to this rule including when you want to access arguments
or
this
, or when you want to be able to debug browserified code.
Right:
let result = '';
const append = a => {
result += a;
};
const combine = (a, b) => {
result = a + b;
};
const getResult = () => result;
Wrong:
let result = '';
const append = (a) => {
result += a;
};
const combine = function(a, b) {
result = a + b;
};
const getResult = () =>
result;
Put short declarations on a single line. For long declarations put a line break after each comma.
Right:
const a = ['hello', 'world'];
const b = {
good: 'code',
'is generally': 'pretty',
};
Wrong:
const a = [
'hello', 'world'
];
const b = {"good": 'code'
, is generally: 'pretty'
};
const c = ['one', 'two',
'three', 'four'];
Programming is not about remembering stupid rules. Use the triple equality operator as it will work just as expected.
Right:
if (a !== '') {
console.log('winning');
}
Wrong:
if (a == '') {
console.log('losing');
}
Do not extend the prototype of native JavaScript objects. Your future self will be forever grateful.
Right:
const a = [];
if (!a.length) {
console.log('winning');
}
Wrong:
Array.prototype.empty = function() {
return !this.length;
}
const a = [];
if (a.empty()) {
console.log('losing');
}
Any non-trivial conditions should be assigned to a descriptively named variable or function:
Right:
const isValidPassword = password.length >= 4 && /^(?=.*\d).{4,}$/.test(password);
if (isValidPassword) {
console.log('winning');
}
Wrong:
if (password.length >= 4 && /^(?=.*\d).{4,}$/.test(password)) {
console.log('losing');
}
Keep your functions short. A good function fits on a slide that the people in the last row of a big room can comfortably read. So don't count on them having perfect vision and limit yourself to ~15 lines of code per function.
To avoid deep nesting of if-statements, always return a function's value as early as possible.
Right:
function isPercentage(val) {
if (val < 0) {
return false;
}
if (val > 100) {
return false;
}
return true;
}
Wrong:
function isPercentage(val) {
if (val >= 0) {
if (val < 100) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Or for this particular example it may also be fine to shorten things even further:
function isPercentage(val) {
var isInRange = (val >= 0 && val <= 100);
return isInRange;
}
To add documentation comments that will be built using jsdocs, use jsdoc block tags. For angular code use the angular tags, see examples.
Try to write comments that explain higher level mechanisms or clarify difficult segments of your code. Don't use comments to restate trivial things.
Right:
/**
* 'ID_SOMETHING=VALUE' -> ['ID_SOMETHING=VALUE', 'SOMETHING', 'VALUE']
* @type {boolean}
*/
const matches = item.match(/ID_([^\n]+)=([^\n]+)/));
/**
* Loads a user. This function has a nasty side effect where a failure to increment a
* redis counter used for statistics will cause an exception. This needs
* to be fixed in a later iteration.
* @param {string} id the user id
* @param {function} cb a callback function that applied to the user
*/
function loadUser(id, cb) {
...
}
Wrong:
/**
* Execute a regex
*/
const matches = item.match(/ID_([^\n]+)=([^\n]+)/);
/**
* Usage: loadUser(5, function() { ... })
*/
function loadUser(id, cb) {
...
}
/**
* Check if the session is valid
*/
const isSessionValid = (session.expires < Date.now());
/** If the session is valid */
if (isSessionValid) {
...
}
Crazy stuff that you will probably never need. Stay away from it.
Do not use setters, they cause more problems for people who try to use your software than they can solve.
Feel free to use getters that are free from side effects, like providing a length property for a collection class.