- Encoding
- Javascript Modus
- Line Length
- Indentation and Whitespaces
- Comments
- Commas and Semicolons
- Variables
- Comparison Operators and Equality
- Operator Spacing and Blocks
- Type Casting and Coercion
- Strings
- Objects
- Arrays
- Properties
- ES6 Variables
- ES6 References
- ES6 Destructuring
- ES6 Strings
- ES6 Functions
- ES6 Arrow Functions
- ES6 Constructors
- ES6 Modules
- ES6 Naming Conventions
This styleguide provides rules and best practices for writing clean, well structured and maintainable code. It has been created to improve cross-project cooperation and reduce the initial time spent on getting familiar with a new project.
You will get a general overview about how to "style" the code followed by some ES6 relevant guidelines.
Note: For most of the general code examples the ES5 syntax is used. Keep in mind not to mix syntaxes if you write in ES6.
This styleguide is obligatory! If you are convinced that your project cannot be implemented without violating some of these rules, please contact us.
- Always use UTF-8 encoding for javascript files.
- ES5 and ES6 are triggered by writing
use strict
:
//bad + error
"use strict"
//good
'use strict';
-
Each line should be no longer than 80 characters. If a line goes longer than 80 characters, it should be wrapped after an operator (comma, plus, etc.). The following line should be indented two levels (eight characters/spaces).
-
Strings longer than 80 characters should be written across multiple lines using string concatenation.
- Always use spaces for indentation in Javascript.
- Use 4 spaces per indentation level (soft tab).
- Place 1 space before the leading brace.
- Place 1 space before the opening parenthesis in control statements (if, while etc.).
- Place no space before the argument list in function calls and declarations.
// bad
if(isJedi){
∙∙fight∙();
}
// bad
if∙(isJedi)∙{∙∙∙
∙∙∙∙fight();∙∙
}∙∙∙∙∙
// good
if∙(isJedi)∙{
∙∙∙∙fight();
}
// bad
function∙fight∙()∙{
∙∙console.log∙('Swooosh!');
}
// good
function∙fight()∙{
∙∙∙∙console.log('Swooosh!');
}
- Set off operators with spaces.
// bad
var x=y+5;
// good
var x = y + 5;
- Use indentation when making long method chains. Use a leading dot, which emphasizes that the line is a method call, not a new statement.
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
- Leave a blank line after blocks and before the next statement.
// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
var obj = {
foo: function() {
},
bar: function() {
}
};
return obj;
// good
var obj = {
foo: function() {
},
bar: function() {
}
};
return obj;
- Do not pad your blocks with blank lines.
// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
-
Every function should have a comment in JsDoc style format. (More Infos: http://usejsdoc.org)
-
Complex code parts should also be commented as inline comment. (Beware of Line Length.)
/**
* [doCrazyStuff description]
* @param {[type]} name [description]
* @param {[type]} value [description]
* @return {[type]} [description]
*/
function doCrazyStuff(name, value) {
// complex codepart description
while(....) {
// super crazy stuff
};
}
- Prefixing your comments with
FIXME
orTODO
helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are FIXME -- need to figure this out or TODO -- need to implement.
- Never use leading commas.
- Also don't add additional trailing commas in objects and arrays.
// bad
var story = [
once
, upon
, aTime
];
// good
var story = [
once,
upon,
aTime
];
// bad
var hero = {
firstName: 'Bob'
, lastName: 'Parr'
, heroName: 'Mr. Incredible'
, superPower: 'strength'
};
// bad
var hero = {
firstName: 'Bob',
lastName: 'Parr',
};
// good
var hero = {
firstName: 'Bob',
lastName: 'Parr',
heroName: 'Mr. Incredible',
superPower: 'strength'
};
- Add semicolons after each statement.
// bad
(function() {
var name = 'Skywalker'
return name
})()
// good
(function() {
var name = 'Skywalker';
return name;
})();
Primitives are:
- string
- number
- boolean
- null
- undefined
Strings should be defined in single quotes.
//bad
var message = "hello";
//good
var message = 'hello';
- Use one var declaration per variable. It's easier to add new variable declarations this way, and you never have to worry about swapping out a ; for a , or introducing punctuation-only diffs.
// bad
var items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, and try to spot the mistake)
var items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
- In a variable definition block, the type of a variable should always be predefined, even if its value is empty. This shows the type of a variable and reserves the correct memory space.
var foo = '';
var bar = [];
var fooBar = {};
var $fooBar = {}; // jQuery
var $fooBar = $(); // empty jQuery Object
- Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
// bad
var i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
var i;
var items = getItems();
var dragonball;
var goSportsTeam = true;
var len;
// good
var items = getItems();
var goSportsTeam = true;
var dragonball;
var length;
var i;
-
Always use
const
,let
,var
to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. -
Use camelCase when naming variables, objects, functions, and instances. Start lowercase.
var fooBar = '';
- Always define variables on top of a scope.
// bad
function() {
test();
console.log('doing stuff..');
//..other stuff..
var name = getName();
if (name === 'test') {
return false;
}
return name;
}
// good
function() {
var name = getName();
test();
console.log('doing stuff..');
//..other stuff..
if (name === 'test') {
return false;
}
return name;
}
- Constructors and class names will be written in PascalCase. Start Uppercase.
var MyKlass = function() {};
- ES5 Constants will always be uppercase. Use
_
to separate words in constants. If you write ES6 and are using theconst
definition you can write in camelCase.
// bad
var pi = 3.141592654;
// good
var PI = 3.141592654; // shows that the variable shouldn't be changed
// good
var PI_PA_PO = 3.141592654;
// good in ES6
const pi = 3.141592654;
- Use
$
for jQuery variables.
$myElement = $('.myElement');
- Use
_
for naming private variables.
_superSecretNumber = 42;
- Use
_$
for private jQuery variables.
_$superSecretElement = $('.topSecret');
- No numeric beginning of variable names.
It's javascript standard and will result in an syntax error.
// bad
var 23bad = 23;
- Avoid single letter names. Be descriptive with your naming and write meaningful variable names.
//Bad
var callback = function(e) {...}
//Good
var mouseMoveHandler = function(e) {...}
- Use readable synonyms in place of reserved words.
- Name your functions. This is helpful for stack traces.
// bad
var log = function(msg) {
console.log(msg);
};
// good
var log = function log(msg) {
console.log(msg);
};
-
Never declare a function in a non-function block (if, for, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.
-
Never use the Function constructor to create a new function.
Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities.
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
- Use
===
and!==
over==
and!=
.
-
Operators with two operands must be preceded and followed by a single space to make the expression clear. Operators include assignments and logical operators.
-
Use braces with all multi-line blocks.
// bad
if (test)
return false;
// good
if (test) {
return false;
}
- If you're using multi-line blocks with if and else, put else on the same line as your if block's closing brace.
// bad
if (test) {
thing1();
}
else {
thing2();
}
// good
if (test) {
thing1();
} else {
thing2();
}
- Perform type coercion at the beginning of the statement. Strings:
// => this.reviewScore = 9;
// bad
var totalScore = this.reviewScore + '';
// good
var totalScore = '' + this.reviewScore;
// bad
var totalScore = '' + this.reviewScore + ' total score';
// good
var totalScore = this.reviewScore + ' total score';
- Use parseInt for Numbers and always with a radix for type casting.
var inputValue = '4';
// bad
var val = new Number(inputValue);
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue, 10);
// good - faster lookup as parseInt is part of window
var val = +inputValue;
- Don't use bit operators!
Why? Too many internal 64 bit to 32 bit (and reverse) convertions.
- Use
Boolean()
or!!
for boolean convertion.
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
- Note: If overused, long strings with concatenation could impact performance.
// bad
var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
// bad
var errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
//bad – but good practice if you don’t use uglify
var errorMessage = [
'This is a super long error that was thrown because ',
'of Batman. When you stop to think about how Batman had anything to do ',
'with this, you would get nowhere fast.'
].join('');
// good
var errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
- When programmatically building up a string, use Array#join instead of string concatenation.
var items;
var messages;
var length;
var i;
messages = [{
state: 'success',
message: 'This one worked.'
}, {
state: 'success',
message: 'This one worked as well.'
}, {
state: 'error',
message: 'This one did not work.'
}];
length = messages.length;
// bad
function inbox(messages) {
items = '<ul>';
for (i = 0; i < length; i++) {
items += '<li>' + messages[i].message + '</li>';
}
return items + '</ul>';
}
// good
function inbox(messages) {
items = [];
for (i = 0; i < length; i++) {
// use direct assignment in this case because we're micro-optimizing.
items[i] = '<li>' + messages[i].message + '</li>';
}
return '<ul>' + items.join('') + '</ul>';
}
- Use the literal syntax for object creation.
// bad
var item = new Object();
// good
var item = {};
- Don't use reserved words as keys. It won't work in IE8. (More info: http://es5.github.io/#x7.6.1)
// bad
var superman = {
default: {
clark: 'kent'
},
private: true
};
// good
var superman = {
defaults: {
clark: 'kent'
},
hidden: true
};
Object literals should have the following format:
- The opening brace should be on the same line as the containing statement.
- Each property-value pair should be indented one level with the first property appearing on the next line after the opening brace.
- Each property-value pair should have an unquoted property name, followed by a colon (no space preceding it), followed by the value. If the value is a function, it should wrap under the property name (and should have a blank line both before and after the function.)
- Additional empty lines may be inserted to group related properties or otherwise improve readability.
- The closing brace should be on a separate line.
// Good
var object = {
key1: value1,
key2: value2,
func: function() {
// do something
},
key3: value3
};
var myNumbers = [1, 2, 3];
- Use the literal syntax for array creation.
// bad
var items = new Array();
// good
var items = [];
// good
var items = [1, 2, ''];
- Use Array#push instead of direct assignment to add items to an array.
var someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
- Use dot notation when accessing properties.
var luke = {
jedi: true,
age: 28
};
// bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
The following section describes only ES6 relevant coding guidelines.
See the general section above for all general guidelines for writing js code.
- Group all your consts and then group all your lets.
Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball = {};
let i = 1;
let length = 42;
- If your file exports a single class, your filename should be exactly the name of the class.
// file contents
class CheckBox {
// ...
}
module.exports = CheckBox;
// in some other file
// bad
var CheckBox = require('./checkBox');
// bad
var CheckBox = require('./check_box');
// good
var CheckBox = require('./CheckBox');
- Use
const
for all of your references; avoid usingvar
.
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
- If you must reassign references, use
let
instead ofvar
.
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
// good
for (let a = 0, b = 10; a < b; a++) {
// let makes 'a' and 'b' only exist inside the for loop
}
- Use property value shorthand.
Why? It is shorter to write and descriptive.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- Group your shorthand properties at the beginning of your object declaration.
Why? It's easier to tell which properties are using the shorthand.
const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
- Use object destructuring when accessing and using multiple properties of an object.
Why? Destructuring saves you from creating temporary references for those properties.
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(obj) {
const { firstName, lastName } = obj;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
- Use array destructuring.
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
- Use object destructuring for multiple return values, not array destructuring.
Why? You can add new properties over time or change the order of things without breaking call sites.
// bad
function processInput(input) {
// then a miracle occurs
return [left, right, top, bottom];
}
// the caller needs to think about the order of return data
const [left, __, top] = processInput(input);
// good
function processInput(input) {
// then a miracle occurs
return { left, right, top, bottom };
}
// the caller selects only the data they need
const { left, right } = processInput(input);
- When programmatically building up strings, use template strings instead of concatenation.
Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
- Use backticks to write multi-line strings.
var longString = `Then took the other, as just as fair,
And having perhaps the better claim
Because it was grassy and wanted wear,
Though as for that the passing there
Had worn them really about the same ...`
- Use default parameter syntax rather than mutating function arguments.
// bad
function handleThings(opts) {
opts = opts || {};
// ...
}
// bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- Always put default parameters last.
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
- When you must use function expressions (as when passing an anonymous function), use arrow function notation.
Why? It creates a version of the function that executes in the context of this, which is usually what you want, and is a more concise syntax.
Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration.
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- In case the expression spans over multiple lines, wrap it in parentheses for better readability.
Why? It shows clearly where the function starts and ends.
// bad
[1, 2, 3].map(number => 'As time went by, the string containing the ' +
`${number} became much longer. So we needed to break it over multiple ` +
'lines.'
);
// good
[1, 2, 3].map(number => (
`As time went by, the string containing the ${number} became much ` +
'longer. So we needed to break it over multiple lines.'
));
If your function only takes a single argument, feel free to omit the parentheses.
Why? Less visual clutter. eslint rules: arrow-parens.
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].reduce((y, x) => x + y);
- Always use class. Avoid manipulating prototype directly.
Why? class syntax is more concise and easier to reason about.
// bad
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
- Use extends for inheritance.
Why? It is a built-in way to inherit prototype functionality without breaking instanceof.
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this._queue[0];
}
// good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
- Methods can return this to help with method chaining.
// bad
Jedi.prototype.jump = function () {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function (height) {
this.height = height;
};
const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined
// good
class Jedi {
jump() {
this.jumping = true;
return this;
}
setHeight(height) {
this.height = height;
return this;
}
}
const luke = new Jedi();
luke.jump()
.setHeight(20);
- Always use modules (
import
/export
) over a non-standard module system. You can always transpile to your preferred module system.
Why? Modules are the future, let's start using the future now.
// bad
const MyModule = require('./MyModule');
module.exports = MyModule.batman;
// ok
import MyModule from './MyModule';
export default MyModule.batman;
// best
import { batman } from './MyModule';
export default batman;
- Do not use wildcard imports.
Why? This makes sure you have a single default export.
// bad
import * as MyModule from './MyModule';
// good
import MyModule from './MyModule';
- And do not export directly from an import.
Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
// bad
// filename batman.js
export { batman as default } from './MyModule';
// good
// filename batman.js
import { batman } from './MyModule';
export default batman;
See also general section!
- Use camelCase when you export-default a function. Your filename should be identical to your function's name.
function makeStyleGuide() {
}
export default makeStyleGuide;
- Use PascalCase when you export a singleton / function library / bare object.
const MyModule = {
batman: {
}
};
export default MyModule;
SASS / CSS:
- [Andy Gutsche (HL)](mailto: [email protected])
- [Marlene Schertler](mailto: [email protected])
Markup / Accessibility:
- [Felix Berger](mailto: [email protected])
- [Wibke Jaeger](mailto: [email protected])
JavaScript:
- [Peter Dematte](mailto: [email protected])
- [Bastian Runge](mailto: [email protected])
Learning ES6
- Draft ECMA 2015 (ES6) Spec
- ExploringJS
- ES6 Compatibility Table
- Comprehensive Overview of ES6 Features
Read This
Tools
- Code Style Linters
Other Styles
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks - Ross Allen
- Popular JavaScript Coding Conventions on Github - JeongHoon Byun
- Multiple var statements in JavaScript, not superfluous - Ben Alman
Further Reading
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- You Might Not Need jQuery - Zack Bloom & Adam Schwartz
- ES6 Features - Luke Hoban
- Frontend Guidelines - Benjamin De Cock
Books
- JavaScript: The Good Parts - Douglas Crockford
- JavaScript Patterns - Stoyan Stefanov
- Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
- High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
- Maintainable JavaScript - Nicholas C. Zakas
- JavaScript Web Applications - Alex MacCaw
- Pro JavaScript Techniques - John Resig
- Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
- Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
- Human JavaScript - Henrik Joreteg
- Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- JSBooks - Julien Bouquillon
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
- Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
- Eloquent JavaScript - Marijn Haverbeke
- You Don't Know JS: ES6 & Beyond - Kyle Simpson
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
Podcasts