diff --git a/README.md b/README.md index dbafdc488d..e96cf78d15 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -# Airbnb JavaScript Style Guide() { +# Grooveshark JavaScript Style Guide() { *A mostly reasonable approach to JavaScript* +*Forked and slightly modified from Airbnb's Style Guide, but still reasonable* + ## Table of Contents @@ -24,7 +26,6 @@ 1. [Accessors](#accessors) 1. [Constructors](#constructors) 1. [Events](#events) - 1. [Modules](#modules) 1. [jQuery](#jquery) 1. [ES5 Compatibility](#es5) 1. [Testing](#testing) @@ -88,14 +89,14 @@ ```javascript // bad var superman = { - default: { clark: 'kent' }, - private: true + default: { clark: 'kent' }, + private: true }; // good var superman = { - defaults: { clark: 'kent' }, - hidden: true + defaults: { clark: 'kent' }, + hidden: true }; ``` @@ -104,17 +105,17 @@ ```javascript // bad var superman = { - class: 'alien' + class: 'alien' }; // bad var superman = { - klass: 'alien' + klass: 'alien' }; // good var superman = { - type: 'alien' + type: 'alien' }; ``` **[[⬆]](#TOC)** @@ -135,8 +136,6 @@ ```javascript var someStack = []; - - // bad someStack[someStack.length] = 'abracadabra'; @@ -153,7 +152,7 @@ // bad for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; + itemsCopy[i] = items[i]; } // good @@ -164,8 +163,8 @@ ```javascript function trigger() { - var args = Array.prototype.slice.call(arguments); - ... + var args = Array.prototype.slice.call(arguments); + ... } ``` @@ -204,9 +203,7 @@ how Batman had anything to do \ with this, you would get nowhere \ fast.'; - - - // good + // good var errorMessage = 'This is a super long error that ' + 'was thrown because of Batman.' + 'When you stop to think about ' + @@ -225,10 +222,10 @@ messages = [{ state: 'success', message: 'This one worked.' - },{ + }, { state: 'success', message: 'This one worked as well.' - },{ + }, { state: 'error', message: 'This one did not work.' }]; @@ -237,24 +234,24 @@ // bad function inbox(messages) { - items = ''; } // good function inbox(messages) { - items = []; + items = []; - for (i = 0; i < length; i++) { - items[i] = messages[i].message; - } + for (i = 0; i < length; i++) { + items[i] = messages[i].message; + } - return ''; + return ''; } ``` @@ -268,17 +265,17 @@ ```javascript // anonymous function expression var anonymous = function() { - return true; + return true; }; // named function expression var named = function named() { - return true; + return true; }; // immediately-invoked function expression (IIFE) (function() { - console.log('Welcome to the Internet. Please follow me.'); + console.log('Welcome to the Internet. Please follow me.'); })(); ``` @@ -288,16 +285,16 @@ ```javascript // bad if (currentUser) { - function test() { - console.log('Nope.'); - } + function test() { + console.log('Nope.'); + } } // good if (currentUser) { - var test = function test() { - console.log('Yup.'); - }; + var test = function test() { + console.log('Yup.'); + }; } ``` @@ -306,12 +303,12 @@ ```javascript // bad function nope(name, options, arguments) { - // ...stuff... + // ...stuff... } // good function yup(name, options, args) { - // ...stuff... + // ...stuff... } ``` @@ -325,8 +322,8 @@ ```javascript var luke = { - jedi: true, - age: 28 + jedi: true, + age: 28 }; // bad @@ -340,12 +337,12 @@ ```javascript var luke = { - jedi: true, - age: 28 + jedi: true, + age: 28 }; function getProp(prop) { - return luke[prop]; + return luke[prop]; } var isJedi = getProp('jedi'); @@ -407,56 +404,56 @@ ```javascript // bad function() { - test(); - console.log('doing stuff..'); + test(); + console.log('doing stuff..'); - //..other stuff.. + //..other stuff.. - var name = getName(); + var name = getName(); - if (name === 'test') { - return false; - } + if (name === 'test') { + return false; + } - return name; + return name; } // good function() { - var name = getName(); + var name = getName(); - test(); - console.log('doing stuff..'); + test(); + console.log('doing stuff..'); - //..other stuff.. + //..other stuff.. - if (name === 'test') { - return false; - } + if (name === 'test') { + return false; + } - return name; + return name; } // bad function() { - var name = getName(); + var name = getName(); - if (!arguments.length) { - return false; - } + if (!arguments.length) { + return false; + } - return true; + return true; } // good function() { - if (!arguments.length) { - return false; - } + if (!arguments.length) { + return false; + } - var name = getName(); + var name = getName(); - return true; + return true; } ``` @@ -471,7 +468,7 @@ // we know this wouldn't work (assuming there // is no notDefined global variable) function example() { - console.log(notDefined); // => throws a ReferenceError + console.log(notDefined); // => throws a ReferenceError } // creating a variable declaration after you @@ -479,17 +476,17 @@ // variable hoisting. Note: the assignment // value of `true` is not hoisted. function example() { - console.log(declaredButNotAssigned); // => undefined - var declaredButNotAssigned = true; + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; } // The interpreter 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; + var declaredButNotAssigned; + console.log(declaredButNotAssigned); // => undefined + declaredButNotAssigned = true; } ``` @@ -497,13 +494,13 @@ ```javascript function example() { - console.log(anonymous); // => undefined + console.log(anonymous); // => undefined - anonymous(); // => TypeError anonymous is not a function + anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { - console.log('anonymous function expression'); - }; + var anonymous = function() { + console.log('anonymous function expression'); + }; } ``` @@ -511,28 +508,28 @@ ```javascript function example() { - console.log(named); // => undefined + console.log(named); // => undefined - named(); // => TypeError named is not a function + named(); // => TypeError named is not a function - superPower(); // => ReferenceError superPower is not defined + superPower(); // => ReferenceError superPower is not defined - var named = function superPower() { - console.log('Flying'); - }; + 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 + // 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 + named(); // => TypeError named is not a function - var named = function named() { - console.log('named'); - }; - } + var named = function named() { + console.log('named'); + }; + } } ``` @@ -540,11 +537,11 @@ ```javascript function example() { - superPower(); // => Flying + superPower(); // => Flying - function superPower() { - console.log('Flying'); - } + function superPower() { + console.log('Flying'); + } } ``` @@ -568,8 +565,8 @@ ```javascript if ([0]) { - // true - // An array is an object, objects evaluate to true + // true + // An array is an object, objects evaluate to true } ``` @@ -578,22 +575,22 @@ ```javascript // bad if (name !== '') { - // ...stuff... + // ...stuff... } // good if (name) { - // ...stuff... + // ...stuff... } // bad if (collection.length > 0) { - // ...stuff... + // ...stuff... } // good if (collection.length) { - // ...stuff... + // ...stuff... } ``` @@ -609,14 +606,14 @@ ```javascript // bad if (test) - return false; + return false; // good if (test) return false; // good if (test) { - return false; + return false; } // bad @@ -624,7 +621,7 @@ // good function() { - return false; + return false; } ``` @@ -644,9 +641,9 @@ // @return element function make(tag) { - // ...stuff... + // ...stuff... - return element; + return element; } // good @@ -659,9 +656,9 @@ */ function make(tag) { - // ...stuff... + // ...stuff... - return element; + return element; } ``` @@ -677,21 +674,21 @@ // bad function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - var type = this._type || 'no type'; + console.log('fetching type...'); + // set the default type to 'no type' + var type = this._type || 'no type'; - return type; + return type; } // good function getType() { - console.log('fetching type...'); + console.log('fetching type...'); - // set the default type to 'no type' - var type = this._type || 'no type'; + // set the default type to 'no type' + var type = this._type || 'no type'; - return type; + return type; } ``` @@ -702,10 +699,10 @@ ```javascript function Calculator() { - // FIXME: shouldn't use a global here - total = 0; + // FIXME: shouldn't use a global here + total = 0; - return this; + return this; } ``` @@ -714,10 +711,10 @@ ```javascript function Calculator() { - // TODO: total should be configurable by an options param - this.total = 0; + // TODO: total should be configurable by an options param + this.total = 0; - return this; + return this; } ``` @@ -726,12 +723,12 @@ ## Whitespace - - Use soft tabs set to 2 spaces + - Use soft tabs set to 4 spaces ```javascript // bad function() { - ∙∙∙∙var name; + ∙∙var name; } // bad @@ -741,7 +738,7 @@ // good function() { - ∙∙var name; + ∙∙∙∙var name; } ``` - Place 1 space before the leading brace. @@ -749,24 +746,24 @@ ```javascript // bad function test(){ - console.log('test'); + console.log('test'); } // good function test() { - console.log('test'); + console.log('test'); } // bad dog.set('attr',{ - age: '1 year', - breed: 'Bernese Mountain Dog' + age: '1 year', + breed: 'Bernese Mountain Dog' }); // good dog.set('attr', { - age: '1 year', - breed: 'Bernese Mountain Dog' + age: '1 year', + breed: 'Bernese Mountain Dog' }); ``` - Place an empty newline at the end of the file. @@ -774,49 +771,18 @@ ```javascript // bad (function(global) { - // ...stuff... + // ...stuff... })(this); ``` ```javascript // good (function(global) { - // ...stuff... + // ...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); - ``` - **[[⬆]](#TOC)** ## Commas @@ -844,10 +810,10 @@ // good var hero = { - firstName: 'Bob', - lastName: 'Parr', - heroName: 'Mr. Incredible', - superPower: 'strength' + firstName: 'Bob', + lastName: 'Parr', + heroName: 'Mr. Incredible', + superPower: 'strength' }; ``` @@ -858,24 +824,24 @@ ```javascript // bad var hero = { - firstName: 'Kevin', - lastName: 'Flynn', + firstName: 'Kevin', + lastName: 'Flynn', }; var heroes = [ - 'Batman', - 'Superman', + 'Batman', + 'Superman', ]; // good var hero = { - firstName: 'Kevin', - lastName: 'Flynn' + firstName: 'Kevin', + lastName: 'Flynn' }; var heroes = [ - 'Batman', - 'Superman' + 'Batman', + 'Superman' ]; ``` @@ -889,20 +855,14 @@ ```javascript // bad (function() { - var name = 'Skywalker' - return name + var name = 'Skywalker' + return name })() // good (function() { - var name = 'Skywalker'; - return name; - })(); - - // good - ;(function() { - var name = 'Skywalker'; - return name; + var name = 'Skywalker'; + return name; })(); ``` @@ -930,7 +890,8 @@ var totalScore = this.reviewScore + ' total score'; ``` - - Use `parseInt` for Numbers and always with a radix for type casting. + - Use `parseInt` for Numbers and always with a radix for type casting, if you want invalid value to be NaN or the radix is not 10. + - If you want invalid values to return 0 and it is a decimal value, use Grooveshark's custom method ```_.toInt()``` ```javascript var inputValue = '4'; @@ -952,20 +913,14 @@ // 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](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. - ```javascript // 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; + var val = _.toInt(inputValue); ``` + - 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), don't. + - Use Grooveshark's custom method _.toInt() instead - it uses bitshifting for performance in the browsers for which it makes a difference. + - Booleans: ```javascript @@ -991,16 +946,16 @@ ```javascript // bad function q() { - // ...stuff... + // ...stuff... } // good function query() { - // ..stuff.. + // ..stuff.. } ``` - - Use camelCase when naming objects, functions, and instances + - Use headlessCamels when naming objects, functions, and instances ```javascript // bad @@ -1009,40 +964,40 @@ var this-is-my-object = {}; function c() {}; var u = new user({ - name: 'Bob Parr' + name: 'Bob Parr' }); // good var thisIsMyObject = {}; function thisIsMyFunction() {}; var user = new User({ - name: 'Bob Parr' + name: 'Bob Parr' }); ``` - - Use PascalCase when naming constructors or classes + - Use ProudCamels when naming constructors or classes ```javascript // bad function user(options) { - this.name = options.name; + this.name = options.name; } var bad = new user({ - name: 'nope' + name: 'nope' }); // good function User(options) { - this.name = options.name; + this.name = options.name; } var good = new User({ - name: 'yup' + name: 'yup' }); ``` - - Use a leading underscore `_` when naming private properties + - Use a leading underscore `_` when naming private properties or methods ```javascript // bad @@ -1058,26 +1013,26 @@ ```javascript // bad function() { - var self = this; - return function() { - console.log(self); - }; + var self = this; + return function() { + console.log(self); + }; } // bad function() { - var that = this; - return function() { - console.log(that); - }; + var that = this; + return function() { + console.log(that); + }; } // good function() { - var _this = this; - return function() { - console.log(_this); - }; + var _this = this; + return function() { + console.log(_this); + }; } ``` @@ -1086,12 +1041,12 @@ ```javascript // bad var log = function(msg) { - console.log(msg); + console.log(msg); }; // good var log = function log(msg) { - console.log(msg); + console.log(msg); }; ``` @@ -1102,6 +1057,7 @@ - Accessor functions for properties are not required - If you do make accessor functions use getVal() and setVal('hello') + - Grooveshark Note: Nope - Use a Backbone Model if you need getters/setters ```javascript // bad @@ -1122,12 +1078,12 @@ ```javascript // bad if (!dragon.age()) { - return false; + return false; } // good if (!dragon.hasAge()) { - return false; + return false; } ``` @@ -1135,17 +1091,17 @@ ```javascript function Jedi(options) { - options || (options = {}); - var lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); + options || (options = {}); + var lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); } Jedi.prototype.set = function(key, val) { - this[key] = val; + this[key] = val; }; Jedi.prototype.get = function(key) { - return this[key]; + return this[key]; }; ``` @@ -1155,30 +1111,31 @@ ## 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! + - Grooveshark Note: Usually you'll never have to worry about this, because Backbone ```javascript function Jedi() { - console.log('new jedi'); + console.log('new jedi'); } // bad Jedi.prototype = { - fight: function fight() { - console.log('fighting'); - }, + fight: function fight() { + console.log('fighting'); + }, - block: function block() { - console.log('blocking'); - } + block: function block() { + console.log('blocking'); + } }; // good Jedi.prototype.fight = function fight() { - console.log('fighting'); + console.log('fighting'); }; Jedi.prototype.block = function block() { - console.log('blocking'); + console.log('blocking'); }; ``` @@ -1187,12 +1144,12 @@ ```javascript // bad Jedi.prototype.jump = function() { - this.jumping = true; - return true; + this.jumping = true; + return true; }; Jedi.prototype.setHeight = function(height) { - this.height = height; + this.height = height; }; var luke = new Jedi(); @@ -1201,13 +1158,13 @@ // good Jedi.prototype.jump = function() { - this.jumping = true; - return this; + this.jumping = true; + return this; }; Jedi.prototype.setHeight = function(height) { - this.height = height; - return this; + this.height = height; + return this; }; var luke = new Jedi(); @@ -1221,16 +1178,16 @@ ```javascript function Jedi(options) { - options || (options = {}); - this.name = options.name || 'no name'; + options || (options = {}); + this.name = options.name || 'no name'; } Jedi.prototype.getName = function getName() { - return this.name; + return this.name; }; Jedi.prototype.toString = function toString() { - return 'Jedi - ' + this.getName(); + return 'Jedi - ' + this.getName(); }; ``` @@ -1248,7 +1205,7 @@ ... $(this).on('listingUpdated', function(e, listingId) { - // do something with listingId + // do something with listingId }); ``` @@ -1261,44 +1218,13 @@ ... $(this).on('listingUpdated', function(e, data) { - // do something with data.listingId + // do something with data.listingId }); ``` **[[⬆]](#TOC)** -## 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 and returns this one. - - 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) { - this.options = options || {}; - } - - FancyInput.noConflict = function noConflict() { - global.FancyInput = previousFancyInput; - return FancyInput; - }; - - global.FancyInput = FancyInput; - }(this); - ``` - - **[[⬆]](#TOC)** - - ## jQuery - Prefix jQuery object variables with a `$`. @@ -1316,25 +1242,25 @@ ```javascript // bad function setSidebar() { - $('.sidebar').hide(); + $('.sidebar').hide(); - // ...stuff... + // ...stuff... - $('.sidebar').css({ - 'background-color': 'pink' - }); + $('.sidebar').css({ + 'background-color': 'pink' + }); } // good function setSidebar() { - var $sidebar = $('.sidebar'); - $sidebar.hide(); + var $sidebar = $('.sidebar'); + $sidebar.hide(); - // ...stuff... + // ...stuff... - $sidebar.css({ - 'background-color': 'pink' - }); + $sidebar.css({ + 'background-color': 'pink' + }); } ``` @@ -1377,7 +1303,7 @@ ```javascript function() { - return true; + return true; } ```