Magnetis JavaScript code styleguide.
- Disclaimer
- Semicolons
- Strict mode
- Context and closures
- Variables
- Objects
- Arrays
- Strings
- Functions
- Naming conventions
- Properties
- Conditional Expressions and equality
- Blocks
- Comments
- Whitespace
- Type checking
- Best practices
- Links
This document is inspired by jQuery Style Guide, idiomatic.js and Airbnb JavaScript Style Guide.
- Yes, please! ASI is very complicated, don't rely on it.
// Bad
(function() {
var name = 'John'
return name
})()
// Good
(function() {
var name = 'John';
return name;
})();
- You should use the strict mode pragma. Just be aware not to use it globally!
// Bad
'use strict';
function doSomething() {
}
function doSomethingElse() {
}
// Good
function doSomething() {
'use strict';
// stuff
}
// Good
(function() {
'use strict';
function doSomething() {
}
function doSomethingElse() {
}
})();
- Always wrap your modules in closures creating a unique context of execution. Throwing things at the global scope can lead to all kinds of weird behaviors.
// Bad
function doAwesomeStuff() {
$('.js-item').fadeIn();
}
function doEvenCoolerStuff() {
$('.js-item').animate({top: 100}, 'fast');
}
// Good
(function($) {
function doAwesomeStuff() {
$('.js-item').fadeIn();
}
function doEvenCoolerStuff() {
$('.js-item').animate({top: 100}, 'fast');
}
})(jQuery);
// Good
var Module = (function() {
function Module() {
// magic happens here
}
return Module;
})();
- Use single
var
definition approach when defining variables.
// Bad
var foo = 'Foo';
var bar = 'Bar';
var baz = 'Baz';
// Good
var foo = 'Foo',
bar = 'Bar',
baz = 'Baz';
- Variables with no startup value should come first.
// Bad
var name = 'John',
surname = 'Doe',
country,
age = 42,
email;
// Good
var country,
email,
name = 'John',
surname = 'Doe',
age = 42;
- Do not follow "comma first" style!
// Bad (OMG, really bad!)
var once
, upon
, aTime;
// Good
var once,
upon,
aTime;
// Bad
var user = {
name: 'John',
, surname: 'Doe'
, age: 42
};
// Good
var user = {
name: 'John',
surname: 'Doe',
age: 42
};
- Use the literal syntax for object creation.
// Bad
var foo = new Object();
// Good
var bar = {};
- Do not use reserved words as keys. They can cause problems in older IE versions.
// Bad
var foo = {
class: 'Foo'
};
// Good
var bar = {
klass: 'Bar'
};
// Good
var baz = {
type: 'Baz'
};
- Use 🐫 camelCase when naming object keys when possible.
// Bad
var user = {
'name': 'John',
'has-children': false,
'is-underage': false,
'age': 42
};
// Good
var user = {
name: 'John',
hasChildren: false,
isUnderage: false,
age: 42
};
- If you need to use quotes to wrap your keys for any reason, be consistent about it:
// Bad
var config = {
development: true,
'markdown-plugin': true,
shouldIgnoreManifest: false,
PersistData: true,
enforcenamespace: true
};
// Good
var config = {
'development': true,
'markdown-plugin': true,
'should-ignore-manifest': false,
'persist-data': true,
'enforce-namespace': true
};
// Good
var config = {
development: true,
markdownPlugin: true,
shouldIgnoreManifest: false,
persistData: true,
enforceNamespace: true
};
- Use the literal syntax for array creation.
// Bad
var foo = new Array();
// Good
var bar = [1, 2, 3];
- If you don't know the array length use
Array.push
.
var groceries = [];
// Bad
groceries[groceries.length] = 'tomato';
// Good
groceries.push('oreo');
- To cleanup an array set its length to zero.
// Bad
var foo = [1, 3, 5];
foo = null;
// Good
var bar = [2, 4, 6];
bar.length = 0;
- To convert an array-like object to an array, use
Array.slice
. - PS: you might want to do this because array-like objects (e.g {'0': 'hello', '1': 'there'} ) don't have methods like '.join()', for more information on this suject read this article
function argsToArray() {
var args = Array.prototype.slice.call(arguments);
}
- Use single quotes
''
for strings.
// Bad
var phil = "Philip Sampaio";
// Good
var luciano = 'Luciano Tavares';
- Concat strings using the plus
+
operator.
var name = 'Rafael';
// Bad
name.concat('Rinaldi');
// Good
name += ' Rinaldi';
- Prefer string concatenation for long strings, always adding line breaks after an operator. Long strings can impact performance big time (benchmark and discussion).
// 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.';
// 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.';
-
To convert objects to string, use the
toString()
method. -
The conversion with
toString()
does not work withnull
andundefined
values. To convert any value to string, concats its value to an empty string. This is useful when you don't care about the value of the conversion (ex: in a logging or tracking system). In case you convert anull
value, it will transform into"null"
. The same rule is applied toundefined
values.
var value = 42;
// Good
value += '';
var empty;
empty += ''; // "undefined"
- Whenever you have more than 3 arguments being passed to a function it's preferable to use an object instead.
// Bad
// Too many arguments
function setUser(firstName, lastName, age, gender, occupation) {
// do stuff
}
setUser('Jon', 'Snow', 25, 'Male', 'Nights-watcher');
// Good
// Use a config/options object instead
function setUser(user) {
// do stuff
}
setUser({
firstName: 'Jon',
lastName: 'Snow',
age: 25,
gender: 'Male',
occupation: 'Nights-watcher'
});
- Use camelCase when naming objects, functions and instances.
// bad
var foo_bar = 'I am messed up';
// good
var fooBar = 'I am alright!';
- Use PascalCase when naming constructors and "classes".
// Bad
function crewMember(name, role) {
this.name = name;
this.role = role;
}
var thales = new crewMember('Thales', 'Desenvolvedor');
// Good
function CrewMember(name, role) {
this.name = name;
this.role = role;
}
var vinicius = new CrewMember('Vinicius', 'Designer');
- Avoid single letter names. Be descriptive and clear.
// Bad
function f() {
// What the hell is this?
}
// Good
function bootstrapFoo() {
// Ah, ok!
}
// Bad
function stuff() {
// "stuff" is too generic
}
// Good
function doAnimationStuff() {
// Now we're talking
}
- Always wrap constructor invocations with brackets. It's going to be easier to pass new constructor values if needed in the future.
// Bad
var foo = new FooBar;
// Good
var bar = new FooBar();
var baz = new FooBar(1, 'lorem');
- Always use a leading underscore
_
when naming private properties and methods.
// Bad
var $name = 'Foo';
var __name = 'Bar';
// Good
var _name = 'Baz';
- When making a reference to
this
name it asself
.
// Bad
function() {
var that = this;
return function() {
console.log(that);
}
}
// Bad
function() {
var _this = this;
return function() {
console.log(this);
}
}
// Good
function() {
var self = this;
return function() {
console.log(self);
}
}
- When naming a Boolean variable, it should start with "is", "has", "should" or "was".
// Bad
var ready = true,
animate = true,
started = false,
animation = true;
// Good
var isReady = true,
shouldAnimate = true,
wasStarted = true,
hasAnimation = true;
- When naming a Boolean function, it should start with "is".
// Bad
function ready() {
return false;
}
// Good
function isReady() {
return true;
}
- When naming an acessor, try to start with "get" or "set". Also explicitly name
value
as getters parameter.
var currentStatus;
// Bad
function status(val) {
if (val) {
currentStatus = val;
}
return currentStatus;
}
// Good
function setStatus(value) {
currentStatus = value;
}
function getStatus() {
return currentStatus;
}
- When naming an event handler, combine its action with the event type.
// Bad
$('.button').click(click);
function click() {
console.log('meh');
}
// Good
$('.button').click(toggleColorOnClick);
function toggleColorOnClick() {
console.log('should toggle color on click!');
}
- When naming class selectors of DOM elements that will have any kind of behavior, add
js
prefix to the name of your component separating words using an hyphen-
.
<ul class="js-navigation-menu">
<li>Foo</li>
<li>Bar</li>
</ul>
var menu = $('.js-navigation-menu');
- Use dot notation to access properties.
var user = {
name: 'John',
age: 42
};
// Bad
var userName = user['name'];
// Good
var userAge = user.age;
- Use subscript notation
[]
to access dynamic properties.
var user = {
name: 'John',
age: 42
};
function getUserInfo(info) {
return user[info];
}
var userName = getUserInfo('name');
- Use
===
and!==
over==
and!=
.
- Always wrap blocks within braces and embrace new lines.
// Bad
if (false)
return;
// Bad
if (false) { return false; }
// Good
if (true) {
return true;
}
// Good
if (true) {
return true;
} else {
return false;
}
-
Don't make trivial and obvious comments, be concise about it. If you caught yourself writing too much documentation for your code, consider a pair programming because you're likely over engineering it.
-
Feel free to use markdown syntax on code comments.
-
No need to use JSDoc syntax since we don't automatically generate documentation.
-
Using
FIXME
,TODO
andNOTE
tags can help other developers understand and maintain your code. You can use it as you want. -
Use documentation block syntax followed by a newline for multiline comments. There are tools available to make it really easy.
// Bad
// Used to match `RegExp` special characters.
// See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
// for more details.
var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;
// Bad
/*
Used to match `RegExp` special characters.
See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
for more details.
*/
var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;
// Good
/**
* Used to match `RegExp` special characters.
* See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
* for more details.
*/
var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;
- Use
//
for single line comments. Place single line comments on a newline above the subject of the comment and add an empty line before the comment.
// Bad
var active = true; // is current tab
// Good
// is current tab
var active = true;
// Bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this._type || 'no type';
return type;
}
// Good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
var type = this._type || 'no type';
return type;
}
- Use soft tabs set to 2 spaces and never mix spaces with tabs.
// Bad
function() {
∙∙∙∙var name;
}
// Bad
function() {
∙var name;
}
// Bad
function() {
⇥var name;
}
// Good
function() {
∙∙var name;
}
- Always add an empty line at the end of your file.
// Bad
(function() {
document.write('Hello World!');
})();
// Good
(function() {
document.write('Hello World!');
})();
↵
- Place 1 space before and after a condition or loop declarations.
// Bad
if(false){return false;}
// Good
if (true) {
return true;
}
// Bad
while(false){console.log('whatever');}
// Good
while (false) {
console.log('alright!');
}
- Set off operators with spaces.
// Bad
var x=y+5;
// Good
var x = y + 5;
- Place 1 space after loop steps and function arguments.
// Bad
for(var i=0;i<10;++i) {
console.log(i);
}
// Good
for (var i = 0; i < 42; ++i) {
console.log(i);
}
// Bad
function setUser(name,surname,age){
// sets user
}
// Good
function setUser(name, surname, age) {
// sets user
}
- In objects that have more than a single property you should break all properties into new lines.
// Bad
var user = {name: 'John', surname: 'Doe', age: 42};
// Good
var user = {
name: 'John',
surname: 'Doe',
age: 42
};
- Add inner spaces when declaring inline objects.
// Bad
var app = {locale: 'pt-br'};
// Good
var app = { locale: 'pt-br' };
- Use indentation when making long method chains.
// Bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// Good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
typeof variable === 'string';
typeof variable === 'number';
typeof variable === 'boolean';
typeof variable === 'object';
Array.isArray(arrayLikeObject);
elem.nodeType === 1;
variable === null;
variable == null;
typeof variable === 'undefined';
variable === undefined;
object.prop === undefined;
object.hasOwnProperty(prop);
'prop' in object;
-
Do not start closures with semi-colons.
-
We encourage you to log important app events and changes in development mode only. Follow the format of
Module/ClassName :: method() :: message
.
function App() {
console.log('App :: App instance created');
}
App.prototype.bootstrap = function() {
console.log('App :: bootstrap() :: App was initialized');
};
- Cache jQuery lookups always when possible.
- Prefer
remove()
overempty()
. - Always favor functional and utility functions of jQuery over Underscore.
- It’s time to start using JavaScript strict mode
- Why is it recommended to have empty line in the end of file?
- Multiple var statements in JavaScript, not superfluous
- Naming methods, properties and objects