Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bumbu/javascriptstyleguide
JavaScript Style Guide
https://github.com/bumbu/javascriptstyleguide
Last synced: about 1 month ago
JSON representation
JavaScript Style Guide
- Host: GitHub
- URL: https://github.com/bumbu/javascriptstyleguide
- Owner: bumbu
- Created: 2012-11-25T18:29:11.000Z (about 12 years ago)
- Default Branch: master
- Last Pushed: 2012-11-25T18:30:59.000Z (about 12 years ago)
- Last Synced: 2024-10-14T04:44:07.060Z (3 months ago)
- Size: 109 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# RapidBoard JavaScript Style Guide
## **Table of Contents**
1. [Types](#types)
1. [Objects](#objects)
1. [Arrays](#arrays)
1. [Strings](#strings)
1. [Functions](#functions)
1. [Properties](#properties)
1. [Variables](#variables)
1. [Hoisting](#hoisting)
1. [Conditional Expressions & Equality](#conditionals)
1. [Blocks](#blocks)
1. [Comments](#comments)
1. [Whitespace](#whitespace)
1. [Leading Commas](#leading-commas)
1. [Semicolons](#semicolons)
1. [Type Casting & Coercion](#type-coercion)
1. [Naming Conventions](#naming-conventions)
1. [Accessors](#accessors)
1. [Constructors](#constructors)
1. [Modules](#modules)
1. [jQuery](#jquery)
1. [ES5 Compatability](#es5)
1. [Testing](#testing)## **Types**
- **Primitives**: When you access a primitive type you work directly on its value
+ `String`
+ `Number`
+ `Boolean`
+ `null`
+ `undefined````javascript
var foo = 1
, bar = foo
;bar = 9;
console.log(foo, bar); // => 1, 9
```- **Complex**: When you access a complex type you work on a reference to its value
+ `Object`
+ `Array`
+ `Function````javascript
var foo = [1, 2]
, bar = foo
;bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
```## **Objects**
- Use the literal syntax for object creation.
```javascript
// bad
var item = new Object();// good
var item = {};
```- Don't use [reserved words](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Reserved_Words) as keys.
```javascript
// bad
var superman = {
class: 'superhero'
, default: { clark: kent }
, private: true
};// good
var superman = {
klass: 'superhero'
, defaults: { clark: kent }
, hidden: true
};
```## **Arrays**
- Use the literal syntax for array creation
```javascript
// bad
var items = new Array();// good
var items = [];
```- When you are managing array length use direct assignment over Array#push. [jsPerf](http://jsperf.com/array-direct-assignment-vs-push/11)
```javascript
var hundredOdds = []
, i
;// bad
for (i = 0; i < 100; i++) {
hundredOdds.push(i * 2 + 1);
}// good
for (i = 0; i < 100; i++) {
hundredOdds[i] = i * 2 + 1;
}
```- If you don't know array length use Array#push.
```javascript
var someStack = []
// bad
, someStack[someStack.length] = 'abracadabra';// good
, someStack.push('abracadabra');
```- When you need to copy an array use Array() constructor. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
```javascript
var len = items.length
, itemsCopy = []
, i
;// bad
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}// good
itemsCopy = Array.apply(null, items);
```## **Strings**
- Use single quotes `''` for strings
```javascript
// bad
var name = "Bob Parr";// good
var name = 'Bob Parr';// bad
var fullName = "Bob" + this.lastName;// good
var fullName = 'Bob' + this.lastName;
```- Strings longer than 80 characters should be written across multiple lines using string concatenation.
```javascript
// 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.'
;
```- When programatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2).
```javascript
var items
, messages
, length
, 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 = '
- ';
- ' + messages[i].message + ' ';
for (i = 0; i < length; i++) {
items += '
}
return items + '
}
// good
function inbox(messages) {
items = [];
for (i = 0; i < length; i++) {
items[i] = messages[i].message;
}
return '
- ' + items.join('
- ') + '
}
```
## **Functions**
- Function expressions:
```javascript
// anonymous function expression
var anonymous = function() {
return true;
};
// named function expression
var named = function named() {
return true;
};
// immediately-invoked function expression (IIFE)
(function() {
console.log('Welcome to the Internet. Please follow me.');
})();
```
- Never declare a function in a non-function block (if, 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.
```javascript
// bad
if (currentUser) {
function test() {
console.log('Nope.');
}
}
// good
if (currentUser) {
var test = function test() {
console.log('Yup.');
};
}
```
- Never name a parameter `arguments`, this will take precendence over the `arguments` object that is given to every function scope.
```javascript
// bad
function nope(name, options, arguments) {
// ...stuff...
}
// good
function yup(name, options, args) {
// ...stuff...
}
```
## **Properties**
- Use dot notation when accessing properties.
```javascript
var luke = {
jedi: true
, age: 28
};
// bad
var isJedi = luke['jedi'];
// good
var isJedi = luke.jedi;
```
- Use subscript notation `[]` when accessing properties with a variable.
```javascript
var luke = {
jedi: true
, age: 28
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi');
```
## **Variables**
- Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that.
```javascript
// bad
superPower = new SuperPower();
// good
var superPower = new SuperPower();
```
- Use one `var` declaration for multiple variables and declare each variable on a newline.
```javascript
// bad
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
// good
var items = getItems()
, goSportsTeam = true
, dragonball = 'z'
;
```
- 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.
```javascript
// bad
var i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
var i, items = getItems(),
dragonball,
goSportsTeam = true,
len;
// good
var items = getItems()
, goSportsTeam = true
, dragonball
, i
, length
;
```
- Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues.
```javascript
// 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;
}
// bad
function() {
var name = getName();
if (!arguments.length) {
return false;
}
return true;
}
// good
function() {
if (!arguments.length) {
return false;
}
var name = getName();
return true;
}
```
## **Hoisting**
- Variable declarations get hoisted to the top of their scope, their assignment does not.
```javascript
// we know this wouldn't work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// The interpretor is hoisting the variable
// declaration to the top of the scope.
// Which means our example could be rewritten as:
function example() {
var declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
```
- Anonymous function expression hoist their variable name, but not the function assignment.
```javascript
function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function() {
console.log('anonymous function expression');
};
}
```
- Named function expressions hoist the variable name, not the function name or the function body.
```javascript
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}
}
```
- Function declarations hoist their name and the function body.
```javascript
function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}
```
- For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/)
## **Conditional Expressions & Equality**
- Use `===` and `!==` over `==` and `!=`.
- Conditional expressions are evaluated using coercion with the `ToBoolean` method and always follow these simple rules:
+ **Objects** evaluate to **true**
+ **Undefined** evaluates to **false**
+ **Null** evaluates to **false**
+ **Booleans** evaluate to **the value of the boolean**
+ **Numbers** evalute to **false** if **+0, -0, or NaN**, otherwise **true**
+ **Strings** evaluate to **false** if an empty string `''`, otherwise **true**
```javascript
if ([0]) {
// true
// An array is an object, objects evaluate to true
}
```
- Use shortcuts.
```javascript
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
```
- For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll
## **Blocks**
- Use braces with all multi-line blocks.
```javascript
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function() { return false; }
// good
function() {
return false;
}
```
## **Comments**
- Use `/** ... */` for multiline comments. Include a description, specify types and values for all parameters and return values.
```javascript
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param tag
// @return element
function make(tag) {
// ...stuff...
return element;
}
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param tag
* @return element
*/
function make(tag) {
// ...stuff...
return element;
}
```
- Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an emptyline before the comment.
```javascript
// 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;
}
```
## **Whitespace**
- Use soft tabs set to 2 spaces
```javascript
// bad
function() {
∙∙∙∙var name;
}
// bad
function() {
∙var name;
}
// good
function() {
∙∙var name;
}
```
- Place 1 space before the leading brace.
```javascript
// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog'
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog'
});
```
- Place an empty newline at the end of the file.
```javascript
// bad
(function(global) {
// ...stuff...
})(this);
```
```javascript
// good
(function(global) {
// ...stuff...
})(this);
```
- Use indentation when making long method chains.
```javascript
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
var leds = stage.selectAll('.led').data(data).enter().append("svg:svg").class('led', true)
.attr('width', (radius + margin) * 2).append("svg:g")
.attr("transform", "translate(" + (radius + margin) + "," + (radius + margin) + ")")
.call(tron.led);
// good
var leds = stage.selectAll('.led')
.data(data)
.enter().append("svg:svg")
.class('led', true)
.attr('width', (radius + margin) * 2)
.append("svg:g")
.attr("transform", "translate(" + (radius + margin) + "," + (radius + margin) + ")")
.call(tron.led);
```
## **Leading Commas**
- **Yip.**
```javascript
// bad
var once,
upon,
aTime;
// good
var once
, upon
, aTime
;
// bad
var hero = {
firstName: 'Bob',
lastName: 'Parr',
heroName: 'Mr. Incredible',
superPower: 'strength'
};
// good
var hero = {
firstName: 'Bob'
, lastName: 'Parr'
, heroName: 'Mr. Incredible'
, superPower: 'strength'
};
```
## **Semicolons**
- **Yup.**
```javascript
// bad
(function() {
var name = 'Skywalker'
return name
})()
// good
(function() {
var name = 'Skywalker';
return name;
})();
// good
;(function() {
var name = 'Skywalker';
return name;
})();
```
## **Type Casting & Coercion**
- Perform type coercion at the beginning of the statement.
- Strings:
```javascript
// => 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.
- If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing.
```javascript
var inputValue = '4';
// bad
var val = new Number(inputValue);
// bad
var val = inputValue >> 0;
// bad
var val = parseInt(inputValue);
// ok
var val = +inputValue;
// good
var val = Number(inputValue);
// good
var val = parseInt(inputValue, 10);
// good
/**
* parseInt was the reason my code was slow.
* Bitshifting the String to coerce it to a
* Number made it a lot faster.
*/
var val = inputValue >> 0;
```
- Booleans:
```javascript
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
```
## **Naming Conventions**
- Avoid single letter names. Be descriptive with your naming.
```javascript
// bad
function q() {
// ...stuff...
}
// good
function query() {
// ..stuff..
}
```
- Use camelCase when naming objects, functions, and instances
```javascript
// bad
var OBJEcttsssss = {};
var this_is_my_object = {};
var this-is-my-object = {};
function c() {};
var u = new user({
name: 'Bob Parr'
});
// good
var thisIsMyObject = {};
function thisIsMyFunction() {};
var user = new User({
name: 'Bob Parr'
});
```
- Use PascalCase when naming constructors or classes
```javascript
// bad
function user(options) {
this.name = options.name;
}
var bad = new user({
name: 'nope'
});
// good
function User(options) {
this.name = options.name;
}
var good = new User({
name: 'yup'
});
```
- Use a leading underscore `_` when naming private properties
```javascript
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
// good
this._firstName = 'Panda';
```
- When saving a reference to `this` use `_this`.
```javascript
// bad
function() {
var self = this;
return function() {
console.log(self);
};
}
// bad
function() {
var that = this;
return function() {
console.log(that);
};
}
// good
function() {
var _this = this;
return function() {
console.log(_this);
};
}
```
- Name your functions. This is helpful for stack traces.
```javascript
// bad
var log = function(msg) {
console.log(msg);
};
// good
var log = function log(msg) {
console.log(msg);
};
```
## **Accessors**
- Accessor functions for properties are not required
- If you do make accessor functions use getVal() and setVal('hello')
```javascript
// bad
dragon.age();
// good
dragon.getAge();
// bad
dragon.age(25);
// good
dragon.setAge(25);
```
- If the property is a boolean, use isVal() or hasVal()
```javascript
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
```
- It's okay to create get() and set() functions, but be consistent.
```javascript
function Jedi(options) {
options || (options = {});
var lightsaber = options.lightsaber || 'blue';
this.set('lightsaber', lightsaber);
}
Jedi.prototype.set = function(key, val) {
this[key] = val;
};
Jedi.prototype.get = function(key) {
return this[key];
};
```
## **Constructors**
- Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base!
```javascript
function Jedi() {
console.log('new jedi');
}
// bad
Jedi.prototype = {
fight: function fight() {
console.log('fighting');
}
, block: function block() {
console.log('blocking');
}
};
// good
Jedi.prototype.fight = function fight() {
console.log('fighting');
};
Jedi.prototype.block = function block() {
console.log('blocking');
};
```
- Methods can return `this` to help with method chaining.
```javascript
// bad
Jedi.prototype.jump = function() {
this.jumping = true;
return true;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
};
var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20) // => undefined
// good
Jedi.prototype.jump = function() {
this.jumping = true;
return this;
};
Jedi.prototype.setHeight = function(height) {
this.height = height;
return this;
};
var luke = new Jedi();
luke.jump()
.setHeight(20);
```
- It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects.
```javascript
function Jedi(options) {
options || (options = {});
this.name = options.name || 'no name';
}
Jedi.prototype.getName = function getName() {
return this.name;
};
Jedi.prototype.toString = function toString() {
return 'Jedi - ' + this.getName();
};
```
## **Modules**
- The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated.
- The file should be named with camelCase, live in a folder with the same name, and match the name of the single export.
- Add a method called noConflict() that sets the exported module to the previous version.
- Always declare `'use strict';` at the top of the module.
```javascript
// fancyInput/fancyInput.js
!function(global) {
'use strict';
var previousFancyInput = global.FancyInput;
function FancyInput(options) {
options || (options = {});
}
FancyInput.noConflict = function noConflict() {
global.FancyInput = previousFancyInput;
};
global.FancyInput = FancyInput;
}(this);
```
## **jQuery**
- Prefix jQuery object variables with a `$`.
```javascript
// bad
var sidebar = $('.sidebar');
// good
var $sidebar = $('.sidebar');
```
- Cache jQuery lookups.
```javascript
// bad
function setSidebar() {
$('.sidebar').hide();
// ...stuff...
$('.sidebar').css({
'background-color': 'pink'
});
}
// good
function setSidebar() {
var $sidebar = $('.sidebar');
$sidebar.hide();
// ...stuff...
$sidebar.css({
'background-color': 'pink'
});
}
```
- For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > .ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
- Use `find` with scoped jQuery object queries.
```javascript
// bad
$('.sidebar', 'ul').hide();
// bad
$('.sidebar').find('ul').hide();
// good
$('.sidebar ul').hide();
// good
$('.sidebar > ul').hide();
// good (slower)
$sidebar.find('ul');
// good (faster)
$($sidebar[0]).find('ul');
```
## **ECMAScript 5 Compatability**
- Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/)
## **Testing**
- **Yup.**
```javascript
function() {
return true;
}
```
## **Source**
[AirBNB JS Styleguide](https://github.com/airbnb/javascript/blob/master/README.md)