GitHub - orionhealth/javascript: JavaScript Style Guide (original) (raw)
**[⬆ back to top](#table-of-contents)**
## Whitespace
- Use hard tabs (set to 4 spaces)
```javascript
// bad
function() {
∙∙∙∙var name;
}
// bad
function() {
∙var name;
}
// bad
function() {
∙∙var name;
}
// good
function() {
var name;
}
Place 1 space before the leading brace.
// 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' });
Set off operators with spaces.
// bad var x=y+5; // good var x = y + 5;
End files with a single newline character.
// bad (function(global) { // ... stuff ... })(this);
// bad (function(global) { // ... stuff ... })(this);↵ ↵
// good (function(global) { // ...stuff... })(this);↵
Remove all trailing whitespace
// bad function() {∙∙ var name; ∙∙ // ... stuff ... } // good function() { var name; // ... stuff ... }
Use indentation when making long method chains. Of course, avoiding using chains this long in the first place is preferable.
// 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);
Commas
Leading commas: Nope.
// 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' };
Additional trailing comma: Nope. This can cause problems with IE6/7 and IE9 if it's in quirksmode. Also, in some implementations of ES3 would add length to an array if it had an additional trailing comma. This was clarified in ES5 (source):
Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.
// bad
var hero = {
firstName: 'Kevin',
lastName: 'Flynn',
};
var heroes = [
'Batman',
'Superman',
];
// good
var hero = {
firstName: 'Kevin',
lastName: 'Flynn'
};
var heroes = [
'Batman',
'Superman'
];
Semicolons
Yup.
// bad (function() { var name = 'Skywalker' return name })() // good (function() { var name = 'Skywalker'; return name; })(); // good (guards against the function becoming an argument when two files with IIFEs are concatenated) ;(function() { var name = 'Skywalker'; return name; })();
Type Casting & Coercion
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; // bad var val = inputValue >> 0; // bad var val = parseInt(inputValue); // good var val = Number(inputValue); // good var val = parseInt(inputValue, 10);
If for whatever reason you are doing something wild and
parseInt
is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you're doing.// 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;
Note: Be careful when using bitshift operations. Numbers are represented as 64-bit values, but Bitshift operations always return a 32-bit integer (source). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. Discussion. Largest signed 32-bit Int is 2,147,483,647:
2147483647 >> 0 //=> 2147483647 2147483648 >> 0 //=> -2147483648 2147483649 >> 0 //=> -2147483647
Booleans:
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. Names representing types should be nouns. Names representing methods should be verbs or verb phrases.
// bad function q() { // ... stuff ... } // good function query() { // ... stuff ... }
Use camelCase when naming objects, functions, and instances. Abbreviations and acronyms should also use camel case when used as a name.
// bad var OBJEcttsssss = {}; var this_is_my_object = {}; function c() {} var u = new user({ name: 'Bob Parr' }); // bad function parseJSON() {}; var XMLDocument; // good var thisIsMyObject = {}; function thisIsMyFunction() {} var user = new User({ name: 'Bob Parr' }); // good function parseJson() {}; var xmlDocument;
Use PascalCase when naming constructors or classes
// 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 Screaming Snake Case for constants
// bad var some_constant = 5; // good var SOME_CONSTANT = 5;
Use a leading underscore
_
when naming private properties// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; // good this._firstName = 'Panda';
It is not recommended that you save a reference to
this
; YUI provides the ability to maintain context either by passing in a context as an argument, or through the use of the YUI bind method. If you absolutely need to save a reference tothis
use_this
.// bad function() { var self = this; return function() { console.log(self); }; } // bad function() { var that = this; return function() { console.log(that); }; } // good function() { return Y.bind(function() { console.log(this); }, this); } // ok function() { var _this = this; return function() { console.log(_this); }; }
Name your functions. This is helpful for stack traces. Note this is not necessary for class methods.
// bad var log = function(msg) { console.log(msg); }; // good var log = function log(msg) { console.log(msg); }; // bad var MyObj = { log: function log(msg) { console.log(msg); } }; // good var MyObj = { log: function(msg) { console.log(msg); } };
Note: IE8 and below exhibit some quirks with named function expressions. See http://kangax.github.io/nfe/ for more info.
Accessors
Accessor functions for properties are not required
If you do make accessor functions use getVal() and setVal('hello')
// bad dragon.age(); // good dragon.getAge(); // bad dragon.age(25); // good dragon.setAge(25);
If the property is a boolean, use isVal() or hasVal()
// bad if (!dragon.age()) { return false; } // good if (!dragon.hasAge()) { return false; }
It's okay to create get() and set() functions, but be consistent.
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!
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.// 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.
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(); };
Events
When firing custom events, avoid locking your code into a specific fire and callback signature by sending all event data in an object passed as the second argument. For example, instead of:
// bad Y.fire('birthday', 'John Cardinal', new Date(1949, 11, 12)); // ... stuff ... Y.on('birthday', function(e, name, dateOfBirth) { // do something with name and dateOfBirth });
prefer:
// good Y.fire('birthday', { name: 'John Cardinal', dateOfBirth: new Date(1949, 11, 12) }); // ... stuff ... Y.on('birthday', function(event) { // do something with event.name and event.dateOfBirth });
YUI
YUI is our primary JavaScript library. Don't pull in jQuery. Any other libraries you wish to use should be discussed with the Common Web team.
Cache Y.Node lookups.
// bad function setSidebar() { Y.one('.sidebar').hide(); // ... stuff ... Y.one('.sidebar').setStyle({ 'backgroundColor': 'pink' }); } // good function setSidebar() { var sidebarNode = Y.one('.sidebar'); sidebarNode.hide(); // ... stuff ... sidebarNode.setStyle({ 'backgroundColor': 'pink' }); }
For DOM queries use Cascading
Y.one('.sidebar ul')
or parent > childY.one('.sidebar > ul')
. jsPerf (using jQuery)Use
one
with scoped Y.Node queries.// bad Y.one('.sidebar').one('ul').hide(); // good Y.one('.sidebar ul').hide(); // good Y.one('.sidebar > ul').hide(); // good sidebarNode.one('ul').hide();
ECMAScript 5 Compatibility
- Ensure any methods you're using are supported in all browsers your product is required to support.
- Refer to Kangax's ES5 compatibility table
Testing
Yup.
function() { return true; }
Performance
- On Layout & Web Performance
- String vs Array Concat
- Try/Catch Cost In a Loop
- Bang Function
- jQuery Find vs Context, Selector
- innerHTML vs textContent for script text
- Long String Concatenation
- Loading...
Resources
Read This
Other Styleguides
Other Styles
- Naming this in nested functions - Christian Johansen
- Conditional Callbacks
- Popular JavaScript Coding Conventions on Github
Further Reading
- Understanding JavaScript Closures - Angus Croll
- Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
- ES6 Features - Luke Hoban
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
- Third Party JavaScript - Ben Vinegar and Anton Kovalyov
Blogs
- DailyJS
- JavaScript Weekly
- JavaScript, JavaScript...
- Bocoup Weblog
- Adequately Good
- NCZOnline
- Perfection Kills
- Ben Alman
- Dmitry Baranovskiy
- Dustin Diaz
- nettuts
In the Wild
This is a list of other organizations that have also forked the original Airbnb JavaScript Style Guide.
- Aan Zee: AanZee/javascript
- Airbnb: airbnb/javascript
- American Insitutes for Research: AIRAST/javascript
- Compass Learning: compasslearning/javascript-style-guide
- DailyMotion: dailymotion/javascript
- Digitpaint digitpaint/javascript
- ExactTarget: ExactTarget/javascript
- Gawker Media: gawkermedia/javascript
- GeneralElectric: GeneralElectric/javascript
- GoodData: gooddata/gdc-js-style
- Grooveshark: grooveshark/javascript
- How About We: howaboutwe/javascript
- Mighty Spring: mightyspring/javascript
- MinnPost: MinnPost/javascript
- ModCloth: modcloth/javascript
- Money Advice Service: moneyadviceservice/javascript
- National Geographic: natgeo/javascript
- National Park Service: nationalparkservice/javascript
- Orion Health: orionhealth/javascript
- Peerby: Peerby/javascript
- Razorfish: razorfish/javascript-style-guide
- reddit: reddit/styleguide/javascript
- REI: reidev/js-style-guide
- Ripple: ripple/javascript-style-guide
- SeekingAlpha: seekingalpha/javascript-style-guide
- Shutterfly: shutterfly/javascript
- TheLadders: TheLadders/javascript
- Userify: userify/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript
Translation
The original Airbnb JavaScript Style Guide is also available in other languages:
- :de: German: timofurrer/javascript-style-guide
- :jp: Japanese: mitsuruog/javacript-style-guide
- :br: Portuguese: armoucar/javascript-style-guide
- :cn: Chinese: adamlu/javascript-style-guide
- :es: Spanish: paolocarrasco/javascript-style-guide
- :kr: Korean: tipjs/javascript-style-guide
- :fr: French: nmussy/javascript-style-guide
- :ru: Russian: uprock/javascript
- :bg: Bulgarian: borislavvv/javascript
The JavaScript Style Guide Guide
Contributors
License
(The MIT License)
Copyright (c) 2014 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
};
```