From 372b042a076d60f7de7f11a221142167ff6b6054 Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Sun, 23 Feb 2014 02:53:21 +0100 Subject: [PATCH 1/6] more crockford style, var for each variable declaration --- README.md | 191 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 3a477b6c50..74ff8a6978 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ -# Airbnb JavaScript Style Guide() { +# hq Javascript Styleguide() { *A mostly reasonable approach to JavaScript* +based on the Airbnb JavaScript Style Guide, changes include: + + - anonymous functions: function () instead of function() + - if else if else: newlines and indent + - variable declaration: var on each line + ## Table of Contents @@ -47,8 +53,8 @@ + `undefined` ```javascript - var foo = 1, - bar = foo; + var foo = 1; + var bar = foo; bar = 9; @@ -61,8 +67,8 @@ + `function` ```javascript - var foo = [1, 2], - bar = foo; + var foo = [1, 2]; + var bar = foo; bar[0] = 9; @@ -267,23 +273,37 @@ - Function expressions: ```javascript - // anonymous function expression - var anonymous = function() { + // anonymous function expression, space between function and parantheses + // bad + var anonymous = function() { + return true; + }; + + // good + var anonymous = function () { return true; }; - // named function expression - var named = function named() { + // named function expression, no space between function name and parantheses + // bad + var named = function named () { return true; }; + // good + function named() { + return true; + }; + + // immediately-invoked function expression (IIFE) - (function() { + (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. + - Crockford: If a function literal is anonymous, there should be one space between the word function and the ( (left parenthesis). If the space is omited, then it can appear that the function's name is function, which is an incorrect reading. - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). ```javascript @@ -323,7 +343,7 @@ ## Properties - - Use dot notation when accessing properties. + - if possible Use dot notation when accessing properties. ```javascript var luke = { @@ -333,9 +353,13 @@ // bad var isJedi = luke['jedi']; - + // good var isJedi = luke.jedi; + + // good + var prop = 'jedi'; + var isJedi = like[prop]; ``` - Use subscript notation `[]` when accessing properties with a variable. @@ -368,47 +392,48 @@ var superPower = new SuperPower(); ``` - - Use one `var` declaration for multiple variables and declare each variable on a newline. + - Use one `var` declaration for each variable and declare each variable on a newline. ```javascript - // bad - var items = getItems(); - var goSportsTeam = true; - var dragonball = 'z'; - - // good + // bad var items = getItems(), goSportsTeam = true, dragonball = 'z'; + // good + var items = getItems(); + var goSportsTeam = true; + var 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; + var i, len, dragonball; + var items = getItems(); + var goSportsTeam = true; // bad - var i, items = getItems(), - dragonball, - goSportsTeam = true, - len; + var i; + var items = getItems(); + var dragonball; + var goSportsTeam = true; + var len; // good - var items = getItems(), - goSportsTeam = true, - dragonball, - length, - i; + var items = getItems(); + var goSportsTeam = true; + var dragonball; + var length; + var i; ``` - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. ```javascript // bad - function() { + function () { test(); console.log('doing stuff..'); @@ -424,7 +449,7 @@ } // good - function() { + function () { var name = getName(); test(); @@ -440,7 +465,7 @@ } // bad - function() { + function () { var name = getName(); if (!arguments.length) { @@ -451,7 +476,7 @@ } // good - function() { + function () { if (!arguments.length) { return false; } @@ -503,7 +528,7 @@ anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { + var anonymous = function () { console.log('anonymous function expression'); }; } @@ -598,6 +623,30 @@ } ``` + - Use correct indentation + + ```javascript + // bad + if (name !== '') { + // ...stuff... + } + else if (name === 'moo') { + // ...stuff... + } + else + { + // ...stuff... + } + + // good + if (name) { + // ...stuff... + } else if (name === 'moo') { + // ...stuff... + } else { + // ...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 **[[⬆]](#TOC)** @@ -605,7 +654,7 @@ ## Blocks - - Use braces with all multi-line blocks. + - Use braces with all multi-line blocks - use multi-line blocks with all braces ```javascript // bad @@ -621,10 +670,10 @@ } // bad - function() { return false; } + function example() { return false; } // good - function() { + function example() { return false; } ``` @@ -731,17 +780,17 @@ ```javascript // bad - function() { + function () { ∙∙∙∙var name; } // bad - function() { + function () { ∙var name; } // good - function() { + function () { ∙∙var name; } ``` @@ -786,14 +835,14 @@ ```javascript // bad - (function(global) { + (function (global) { // ...stuff... })(this); ``` ```javascript // good - (function(global) { + (function (global) { // ...stuff... })(this); @@ -901,19 +950,19 @@ ```javascript // bad - (function() { + (function () { var name = 'Skywalker' return name })() // good - (function() { + (function () { var name = 'Skywalker'; return name; })(); // good - ;(function() { + ;(function () { var name = 'Skywalker'; return name; })(); @@ -1055,50 +1104,41 @@ }); ``` - - 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`. + - When saving a reference to `this` use `that`. ```javascript // bad - function() { + function () { var self = this; - return function() { + return function () { console.log(self); }; } // bad - function() { - var that = this; - return function() { - console.log(that); + function () { + var _this = this; + return function () { + console.log(_this); }; } // good - function() { - var _this = this; - return function() { - console.log(_this); + function () { + var that = this; + return function () { + console.log(that); }; } + ``` - Name your functions. This is helpful for stack traces. ```javascript // bad - var log = function(msg) { + var log = function (msg) { console.log(msg); }; @@ -1153,11 +1193,11 @@ this.set('lightsaber', lightsaber); } - Jedi.prototype.set = function(key, val) { + Jedi.prototype.set = function (key, val) { this[key] = val; }; - Jedi.prototype.get = function(key) { + Jedi.prototype.get = function (key) { return this[key]; }; ``` @@ -1199,12 +1239,12 @@ ```javascript // bad - Jedi.prototype.jump = function() { + Jedi.prototype.jump = function () { this.jumping = true; return true; }; - Jedi.prototype.setHeight = function(height) { + Jedi.prototype.setHeight = function (height) { this.height = height; }; @@ -1213,12 +1253,12 @@ luke.setHeight(20) // => undefined // good - Jedi.prototype.jump = function() { + Jedi.prototype.jump = function () { this.jumping = true; return this; }; - Jedi.prototype.setHeight = function(height) { + Jedi.prototype.setHeight = function (height) { this.height = height; return this; }; @@ -1506,6 +1546,7 @@ - :ru: **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - :bg: **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + ## The JavaScript Style Guide Guide - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) From df8a7f42c3a0db32f44b61f7c079887dc2396cbe Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Sun, 23 Feb 2014 02:55:21 +0100 Subject: [PATCH 2/6] trailing comma allowed in node.js --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74ff8a6978..6f7397846e 100644 --- a/README.md +++ b/README.md @@ -917,8 +917,10 @@ based on the Airbnb JavaScript Style Guide, changes include: > 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. + > You may use trailing comma in server-side (Node.js) scripts + ```javascript - // bad + // bad (ok in nodejs) var hero = { firstName: 'Kevin', lastName: 'Flynn', From aa498309afe16a31a998f7c7bacb6f4ff8c55de8 Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Sun, 23 Feb 2014 02:55:37 +0100 Subject: [PATCH 3/6] removed linters --- .../SublimeLinter.sublime-settings | 73 ------------------- linters/jshintrc | 57 --------------- 2 files changed, 130 deletions(-) delete mode 100644 linters/SublimeLinter/SublimeLinter.sublime-settings delete mode 100644 linters/jshintrc diff --git a/linters/SublimeLinter/SublimeLinter.sublime-settings b/linters/SublimeLinter/SublimeLinter.sublime-settings deleted file mode 100644 index 12360f3f1c..0000000000 --- a/linters/SublimeLinter/SublimeLinter.sublime-settings +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Airbnb JSHint settings for use with SublimeLinter and Sublime Text 2. - * - * 1. Install SublimeLinter at https://github.com/SublimeLinter/SublimeLinter - * 2. Open user preferences for the SublimeLinter package in Sublime Text 2 - * * For Mac OS X go to _Sublime Text 2_ > _Preferences_ > _Package Settings_ > _SublimeLinter_ > _Settings - User_ - * 3. Paste the contents of this file into your settings file - * 4. Save the settings file - * - * @version 0.3.0 - * @see https://github.com/SublimeLinter/SublimeLinter - * @see http://www.jshint.com/docs/ - */ -{ - "jshint_options": - { - /* - * ENVIRONMENTS - * ================= - */ - - // Define globals exposed by modern browsers. - "browser": true, - - // Define globals exposed by jQuery. - "jquery": true, - - // Define globals exposed by Node.js. - "node": true, - - /* - * ENFORCING OPTIONS - * ================= - */ - - // Force all variable names to use either camelCase style or UPPER_CASE - // with underscores. - "camelcase": true, - - // Prohibit use of == and != in favor of === and !==. - "eqeqeq": true, - - // Suppress warnings about == null comparisons. - "eqnull": true, - - // Enforce tab width of 2 spaces. - "indent": 2, - - // Prohibit use of a variable before it is defined. - "latedef": true, - - // Require capitalized names for constructor functions. - "newcap": true, - - // Enforce use of single quotation marks for strings. - "quotmark": "single", - - // Prohibit trailing whitespace. - "trailing": true, - - // Prohibit use of explicitly undeclared variables. - "undef": true, - - // Warn when variables are defined but never used. - "unused": true, - - // Enforce line length to 80 characters - "maxlen": 80, - - // Enforce placing 'use strict' at the top function scope - "strict": true - } -} diff --git a/linters/jshintrc b/linters/jshintrc deleted file mode 100644 index d3b47148a8..0000000000 --- a/linters/jshintrc +++ /dev/null @@ -1,57 +0,0 @@ -{ - /* - * ENVIRONMENTS - * ================= - */ - - // Define globals exposed by modern browsers. - "browser": true, - - // Define globals exposed by jQuery. - "jquery": true, - - // Define globals exposed by Node.js. - "node": true, - - /* - * ENFORCING OPTIONS - * ================= - */ - - // Force all variable names to use either camelCase style or UPPER_CASE - // with underscores. - "camelcase": true, - - // Prohibit use of == and != in favor of === and !==. - "eqeqeq": true, - - // Suppress warnings about == null comparisons. - "eqnull": true, - - // Enforce tab width of 2 spaces. - "indent": 2, - - // Prohibit use of a variable before it is defined. - "latedef": true, - - // Require capitalized names for constructor functions. - "newcap": true, - - // Enforce use of single quotation marks for strings. - "quotmark": "single", - - // Prohibit trailing whitespace. - "trailing": true, - - // Prohibit use of explicitly undeclared variables. - "undef": true, - - // Warn when variables are defined but never used. - "unused": true, - - // Enforce line length to 80 characters - "maxlen": 80, - - // Enforce placing 'use strict' at the top function scope - "strict": true -} From eae3085b38c9251a98d53f5fda6730891fb94854 Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Sun, 20 Apr 2014 12:41:16 +0200 Subject: [PATCH 4/6] small changes --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6f7397846e..b12cc3f4a5 100644 --- a/README.md +++ b/README.md @@ -351,10 +351,10 @@ based on the Airbnb JavaScript Style Guide, changes include: age: 28 }; - // bad + // good - no problems with minimizers/obfuscators var isJedi = luke['jedi']; - // good + // ok - take care with minimizers/obfuscators! var isJedi = luke.jedi; // good @@ -395,11 +395,11 @@ based on the Airbnb JavaScript Style Guide, changes include: - Use one `var` declaration for each variable and declare each variable on a newline. ```javascript - // bad + // ok var items = getItems(), goSportsTeam = true, dragonball = 'z'; - // good + // better var items = getItems(); var goSportsTeam = true; var dragonball = 'z'; @@ -1139,12 +1139,12 @@ based on the Airbnb JavaScript Style Guide, changes include: - Name your functions. This is helpful for stack traces. ```javascript - // bad + // ok var log = function (msg) { console.log(msg); }; - // good + // better var log = function log(msg) { console.log(msg); }; From e173e2729d16c92a15b1b0c4de06c39441ff9e0b Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Fri, 25 Jul 2014 16:08:37 +0200 Subject: [PATCH 5/6] jscs --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 README.md diff --git a/README.md b/README.md old mode 100644 new mode 100755 From 4291437495c1a5c941e97eb5838795d58337bb4b Mon Sep 17 00:00:00 2001 From: hobbyquaker Date: Fri, 25 Jul 2014 16:08:55 +0200 Subject: [PATCH 6/6] jscs --- gruntfile.js | 65 ++++ package.json | 6 + styletest.js | 952 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1023 insertions(+) create mode 100755 gruntfile.js create mode 100755 package.json create mode 100755 styletest.js diff --git a/gruntfile.js b/gruntfile.js new file mode 100755 index 0000000000..9e0f188932 --- /dev/null +++ b/gruntfile.js @@ -0,0 +1,65 @@ +// To use this file in WebStorm, right click on the file name in the Project Panel (normally left) and select "Open Grunt Console" + +/** @namespace __dirname */ + +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + + // Javascript code styler + jscs: { + all: { + src: [ "styletest.js "], + options: { + force: true, + "requireCurlyBraces": ["if","else","for","while","do","try","catch","case","default"], + "requireSpaceAfterKeywords": ["if","else","for","while","do","switch","return","try","catch"], +// "requireSpaceBeforeBlockStatements": true, + "requireParenthesesAroundIIFE": true, + "requireSpacesInFunctionExpression": {"beforeOpeningCurlyBrace": true }, + "requireSpacesInAnonymousFunctionExpression": {"beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true}, + "requireSpacesInNamedFunctionExpression": {"beforeOpeningCurlyBrace": true}, + "requireSpacesInFunctionDeclaration": {"beforeOpeningCurlyBrace": true}, + "disallowMultipleVarDecl": true, + "requireBlocksOnNewline": true, + "disallowEmptyBlocks": true, + "disallowSpacesInsideObjectBrackets": true, + "disallowSpacesInsideArrayBrackets": true, + "disallowSpaceAfterObjectKeys": true, + "requireCommaBeforeLineBreak": true, + //"requireAlignedObjectValues": "all", + "requireOperatorBeforeLineBreak": ["?", "+", "-", "/","*", "=", "==", "===", "!=", "!==", ">", ">=", "<","<="], + "disallowLeftStickedOperators": ["?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="], + "requireRightStickedOperators": ["!"], + "disallowRightStickedOperators": ["?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", ">=", "<", "<="], + "requireLeftStickedOperators": [","], + "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], + "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], + "requireSpaceBeforeBinaryOperators": ["+","-","/","*","=","==","===","!=","!=="], + "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], + //"validateIndentation": 4, + //"validateQuoteMarks": { "mark": "\"", "escape": true }, + "disallowMixedSpacesAndTabs": true, + "disallowKeywordsOnNewLine": ["else", "catch"] + + } + } + } + + }); + + var gruntTasks = [ + 'grunt-jscs-checker' + ]; + + var i; + + for (i in gruntTasks) { + grunt.loadNpmTasks(gruntTasks[i]); + } + + grunt.registerTask('default', [ + 'jscs' + ]); +}; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100755 index 0000000000..d3c4cfbd16 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "grunt": "~0.4.4", + "grunt-jscs-checker": "~0.4.1" + } +} \ No newline at end of file diff --git a/styletest.js b/styletest.js new file mode 100755 index 0000000000..22d3efe907 --- /dev/null +++ b/styletest.js @@ -0,0 +1,952 @@ +// bad +var item1 = new Object(); + +// good +var item2 = {}; + + +// Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61) + + +// bad +var superman1 = { + default: {clark: 'kent'}, + private: true +}; + +// good +var superman2 = { + defaults: {clark: 'kent'}, + hidden: true +}; + + +// bad +var items1 = new Array(); + +// good +var items2 = []; + + +// If you don't know array length use Array#push. + + +var someStack = []; + + +// bad +someStack[someStack.length] = 'abracadabra'; + +// good +someStack.push('abracadabra'); + + +// When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) + + +var len1 = items.length; +var itemsCopy1 = []; +var i0; + +// bad +for (i0 = 0; i0 < len; i0++) { + itemsCopy[i0] = items[i0]; +} + +// good +itemsCopy = items.slice(); + + + +// Use single quotes ' for strings + + +// bad +var name1 = "Bob Parr"; + +// good +var name2 = 'Bob Parr'; + +// bad +var fullName1 = "Bob " + this.lastName; + +// good +var fullName2 = 'Bob ' + this.lastName; + +// Strings longer than 80 characters should be written across multiple lines using string concatenation. +// Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40) + + +// bad +var errorMessage1 = '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 errorMessage2 = '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 errorMessage3 = '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). + +var items3; +var messages; +var length2; +var i2; + +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 inbox1(messages) { + items = '
    '; + + for (i = 0; i < length; i++) { + items += '
  • ' + messages[i].message + '
  • '; + } + + return items + '
'; +} + +// good +function inbox2(messages) { + items = []; + + for (i = 0; i < length; i++) { + items[i] = messages[i].message; + } + + return '
  • ' + items.join('
  • ') + '
'; +} + + + + +// anonymous function expression, space between function and parantheses +// bad +var anonymous1 = function() { + return true; +}; + +// good +var anonymous2 = function () { + return true; +}; + +// named function expression, no space between function name and parantheses +// bad +var named1 = function named () { + return true; +}; +// good +function named2() { + 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. +// Crockford: If a function literal is anonymous, there should be one space between the word function and the ( (left parenthesis). If the space is omited, then it can appear that the function's name is function, which is an incorrect reading. +// - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). + + +// bad +if (currentUser) { + function test() { + console.log('Nope.'); + } +} + +// good +var test; +if (currentUser) { + test = function test() { + console.log('Yup.'); + }; +} + + +// Never name a parameter `arguments`, this will take precedence over the `arguments` object that is given to every function scope. + + +// bad +function nope(name, options, arguments) { + doStuff(); +} + +// good +function yup(name, options, args) { + doStuff(); +} + + + +// if possible Use dot notation when accessing properties. + + +var luke1 = { + jedi: true, + age: 28 +}; + +// good - no problems with minimizers/obfuscators +var isJedi1 = luke1['jedi']; + +// ok - take care with minimizers/obfuscators! +var isJedi2 = luke1.jedi; + +// good +var prop = 'jedi'; +var isJedi3 = like[prop]; + +// Use subscript notation `[]` when accessing properties with a variable. + +var luke2 = { + jedi: true, + age: 28 +}; + +function getProp(prop) { + return luke[prop]; +} + +var isJedi3 = getProp('jedi'); + + + + + +// 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. + + +// bad +superPower1 = new SuperPower(); + +// good +var superPower2 = new SuperPower(); + + +// Use one `var` declaration for each variable and declare each variable on a newline. + + +// bad +var items4 = getItems(), + goSportsTeam1 = true, + dragonball1 = 'z'; + +// better +var items5 = getItems(); +var goSportsTeam2 = true; +var dragonball2 = '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. + + +// bad +var i1, len1, dragonball1; +var items6 = getItems(); +var goSportsTeam1 = true; + +// bad +var i2; +var items7 = getItems(); +var dragonball2; +var goSportsTeam2 = true; +var len2; + +// good +var items8 = getItems(); +var goSportsTeam3 = true; +var dragonball3; +var length; +var i3; + + + +// Use `===` and `!==` over `==` and `!=`. +// Conditional expressions are evaluated using coercion with the `ToBoolean` method and always follow these simple rules: + + +// Use shortcuts. + + +// bad +if (name !== '') { + doStuff(); +} + +// good +if (name) { + doStuff(); +} + +// bad +if (collection.length > 0) { + doStuff(); +} + +// good +if (collection.length) { + doStuff(); +} + + +// Use correct indentation + + +// bad +if (name !== '') { + doStuff(); +} +else if (name === 'moo') { + doStuff(); +} +else +{ + doStuff(); +} + +// good +if (name) { + doStuff(); +} else if (name === 'moo') { + doStuff(); +} else { + doStuff(); +} + +// For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll + + +// Use braces with all multi-line blocks - use multi-line blocks with all braces + + + + +function testFunction(test) { + + // bad + if (test) + return false; + + // good + if (test) return false; + + // good + if (test) { + return false; + } +} + + +// bad +function example() { return false; } + +// good +function example() { + return false; +} + + + + +// Use `/** ... */` for multiline comments. Include a description, specify types and values for all parameters and return values. + + +// bad +// make() returns a new element +// based on the passed in tag name +// +// @param tag +// @return element +function make(tag) { + + doStuff(); + + return element; +} + +// good +/** + * make() returns a new element + * based on the passed in tag name + * + * @param tag + * @return element + */ +function make(tag) { + + doStuff(); + + return element; +} + + +// Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put 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 4 spaces + +// bad +function testFunction1() { + var name; +} + +// bad +function testFunction2() { + var name; +} + +// good +function testFunction3() { + 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; + + + + + +// 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(); + +// 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: **Nope.** + + +// bad +var once1 + , upon1 + , aTime1; + +// good +var once2, + upon2, + aTime2; + +// bad +var hero1 = { + firstName: 'Bob' + , lastName: 'Parr' + , heroName: 'Mr. Incredible' + , superPower: 'strength' +}; + +// good +var hero2 = { + 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](http://es5.github.io/#D)): + +// 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. + +// You may use trailing comma in server-side (Node.js) scripts + + +// bad (ok in nodejs) +var hero3 = { + firstName: 'Kevin', + lastName: 'Flynn', +}; + +var heroes1 = [ + 'Batman', + 'Superman', +]; + +// good +var hero4 = { + firstName: 'Kevin', + lastName: 'Flynn' +}; + +var heroes2 = [ + 'Batman', + 'Superman' +]; + + + + +// use semicolons + + + // 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: + + +// => 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](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. +// **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109) + + +// 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: + + +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. + + +// bad +function q() { + doStuff(); +} + +// good +function query() { + // ..stuff.. +} + + +// Use camelCase when naming objects, functions, and instances + + +// bad +var OBJEcttsssss = {}; +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 + + +// 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' +}); + + + + +// Name your functions. This is helpful for stack traces. + + +// ok +var log = function (msg) { + console.log(msg); +}; + +// better +var log = function log(msg) { + console.log(msg); +}; + + + + + + + +// 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() + + + +function testFunction() { + + // 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 attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: + + +// bad +$(this).trigger('listingUpdated', listing.id); + + + +$(this).on('listingUpdated', function (e, listingId) { + // do something with listingId +}); + + +// prefer: + + +// good +$(this).trigger('listingUpdated', {listingId: listing.id}); + + +$(this).on('listingUpdated', function (e, data) { + // do something with data.listingId +}); + + + +