diff --git a/README.md b/README.md index 02ecc75ee6..5c1913cc55 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,21 @@ *A mostly reasonable approach to JavaScript* +[For our old ES5-only guide click here](es5/). ## Table of Contents 1. [Types](#types) + 1. [References](#references) 1. [Objects](#objects) 1. [Arrays](#arrays) + 1. [Destructuring](#destructuring) 1. [Strings](#strings) 1. [Functions](#functions) + 1. [Arrow Functions](#arrow-functions) + 1. [Constructors](#constructors) + 1. [Modules](#modules) + 1. [Iterators and Generators](#iterators-and-generators) 1. [Properties](#properties) 1. [Variables](#variables) 1. [Hoisting](#hoisting) @@ -24,11 +31,10 @@ 1. [Type Casting & Coercion](#type-casting--coercion) 1. [Naming Conventions](#naming-conventions) 1. [Accessors](#accessors) - 1. [Constructors](#constructors) 1. [Events](#events) - 1. [Modules](#modules) 1. [jQuery](#jquery) 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) + 1. [ECMAScript 6 Styles](#ecmascript-6-styles) 1. [Testing](#testing) 1. [Performance](#performance) 1. [Resources](#resources) @@ -50,8 +56,8 @@ + `undefined` ```javascript - var foo = 1; - var bar = foo; + const foo = 1; + let bar = foo; bar = 9; @@ -64,8 +70,8 @@ + `function` ```javascript - var foo = [1, 2]; - var bar = foo; + const foo = [1, 2]; + const bar = foo; bar[0] = 9; @@ -74,29 +80,77 @@ **[⬆ back to top](#table-of-contents)** +## References + + - Use `const` for all of your references; avoid using `var`. + + > Why? This ensures that you can't reassign your references (mutation), which can lead to bugs and difficult to comprehend code. + + ```javascript + // bad + var a = 1; + var b = 2; + + // good + const a = 1; + const b = 2; + ``` + + - If you must mutate references, use `let` instead of `var`. + + > Why? `let` is block-scoped rather than function-scoped like `var`. + + ```javascript + // bad + var count = 1; + if (true) { + count += 1; + } + + // good, use the let. + let count = 1; + if (true) { + count += 1; + } + ``` + + - Note that both `let` and `const` are block-scoped. + + ```javascript + // const and let only exist in the blocks they are defined in. + { + let a = 1; + const b = 1; + } + console.log(a); // ReferenceError + console.log(b); // ReferenceError + ``` + +**[⬆ back to top](#table-of-contents)** + ## Objects - Use the literal syntax for object creation. ```javascript // bad - var item = new Object(); + const item = new Object(); // good - var item = {}; + const item = {}; ``` - 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). ```javascript // bad - var superman = { + const superman = { default: { clark: 'kent' }, private: true }; // good - var superman = { + const superman = { defaults: { clark: 'kent' }, hidden: true }; @@ -106,21 +160,118 @@ ```javascript // bad - var superman = { + const superman = { class: 'alien' }; // bad - var superman = { + const superman = { klass: 'alien' }; // good - var superman = { + const superman = { type: 'alien' }; ``` + + - Use computed property names when creating objects with dynamic property names. + + > Why? They allow you to define all the properties of an object in one place. + + ```javascript + + function getKey(k) { + return `a key named ${k}`; + } + + // bad + const obj = { + id: 5, + name: 'San Francisco' + }; + obj[getKey('enabled')] = true; + + // good + const obj = { + id: 5, + name: 'San Francisco', + [getKey('enabled')]: true + }; + ``` + + + - Use object method shorthand. + + ```javascript + // bad + const atom = { + value: 1, + + addValue: function (value) { + return atom.value + value; + } + }; + + // good + const atom = { + value: 1, + + addValue(value) { + return atom.value + value; + } + }; + ``` + + + - Use property value shorthand. + + > Why? It is shorter to write and descriptive. + + ```javascript + const lukeSkywalker = 'Luke Skywalker'; + + // bad + const obj = { + lukeSkywalker: lukeSkywalker + }; + + // good + const obj = { + lukeSkywalker + }; + ``` + + - Group your shorthand properties at the beginning of your object declaration. + + > Why? It's easier to tell which properties are using the shorthand. + + ```javascript + const anakinSkywalker = 'Anakin Skywalker'; + const lukeSkywalker = 'Luke Skywalker'; + + // bad + const obj = { + episodeOne: 1, + twoJedisWalkIntoACantina: 2, + lukeSkywalker, + episodeThree: 3, + mayTheFourth: 4, + anakinSkywalker + }; + + // good + const obj = { + lukeSkywalker, + anakinSkywalker, + episodeOne: 1, + twoJedisWalkIntoACantina: 2, + episodeThree: 3, + mayTheFourth: 4 + }; + ``` + **[⬆ back to top](#table-of-contents)** ## Arrays @@ -129,16 +280,16 @@ ```javascript // bad - var items = new Array(); + const items = new Array(); // good - var items = []; + const items = []; ``` - Use Array#push instead of direct assignment to add items to an array. ```javascript - var someStack = []; + const someStack = []; // bad @@ -148,50 +299,108 @@ someStack.push('abracadabra'); ``` - - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) + + - Use array spreads `...` to copy arrays. ```javascript - var len = items.length; - var itemsCopy = []; - var i; - // bad + const len = items.length; + const itemsCopy = []; + let i; + for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good - itemsCopy = items.slice(); + const itemsCopy = [...items]; + ``` + - To convert an array-like object to an array, use Array#from. + + ```javascript + const foo = document.querySelectorAll('.foo'); + const nodes = Array.from(foo); ``` - - To convert an array-like object to an array, use Array#slice. +**[⬆ back to top](#table-of-contents)** + +## Destructuring + + - Use object destructuring when accessing and using multiple properties of an object. + + > Why? Destructuring saves you from creating temporary references for those properties. ```javascript - function trigger() { - var args = Array.prototype.slice.call(arguments); - ... + // bad + function getFullName(user) { + const firstName = user.firstName; + const lastName = user.lastName; + + return `${firstName} ${lastName}`; + } + + // good + function getFullName(obj) { + const { firstName, lastName } = obj; + return `${firstName} ${lastName}`; + } + + // best + function getFullName({ firstName, lastName }) { + return `${firstName} ${lastName}`; } ``` -**[⬆ back to top](#table-of-contents)** + - Use array destructuring. + ```javascript + const arr = [1, 2, 3, 4]; -## Strings + // bad + const first = arr[0]; + const second = arr[1]; - - Use single quotes `''` for strings. + // good + const [first, second] = arr; + ``` + + - Use object destructuring for multiple return values, not array destructuring. + + > Why? You can add new properties over time or change the order of things without breaking call sites. ```javascript // bad - var name = "Bob Parr"; + function processInput(input) { + // then a miracle occurs + return [left, right, top, bottom]; + } + + // the caller needs to think about the order of return data + const [left, __, top] = processInput(input); // good - var name = 'Bob Parr'; + function processInput(input) { + // then a miracle occurs + return { left, right, top, bottom }; + } + + // the caller selects only the data they need + const { left, right } = processInput(input); + ``` + + +**[⬆ back to top](#table-of-contents)** +## Strings + + - Use single quotes `''` for strings. + + ```javascript // bad - var fullName = "Bob " + this.lastName; + const name = "Bob Parr"; // good - var fullName = 'Bob ' + this.lastName; + const name = 'Bob Parr'; ``` - Strings longer than 80 characters should be written across multiple lines using string concatenation. @@ -199,62 +408,39 @@ ```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.'; + const 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 \ + const 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 ' + + const 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 programmatically 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; - var messages; - var length; - var i; - - messages = [{ - state: 'success', - message: 'This one worked.' - }, { - state: 'success', - message: 'This one worked as well.' - }, { - state: 'error', - message: 'This one did not work.' - }]; + + - When programmatically building up strings, use template strings instead of concatenation. - length = messages.length; + > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. + ```javascript // bad - function inbox(messages) { - items = ''; + // bad + function sayHi(name) { + return ['How are you, ', name, '?'].join(); } // good - function inbox(messages) { - items = []; - - for (i = 0; i < length; i++) { - // use direct assignment in this case because we're micro-optimizing. - items[i] = '
  • ' + messages[i].message + '
  • '; - } - - return ''; + function sayHi(name) { + return `How are you, ${name}?`; } ``` @@ -263,21 +449,25 @@ ## Functions - - Function expressions: + - Use function declarations instead of function expressions. + + > Why? Function declarations are named, so they're easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use [Arrow Functions](#arrow-functions) in place of function expressions. ```javascript - // anonymous function expression - var anonymous = function() { - return true; + // bad + const foo = function () { }; - // named function expression - var named = function named() { - return true; - }; + // good + function foo() { + } + ``` + + - Function expressions: + ```javascript // immediately-invoked function expression (IIFE) - (function() { + (() => { console.log('Welcome to the Internet. Please follow me.'); })(); ``` @@ -294,9 +484,9 @@ } // good - var test; + let test; if (currentUser) { - test = function test() { + test = () => { console.log('Yup.'); }; } @@ -316,8 +506,314 @@ } ``` + + - Never use `arguments`, opt to use rest syntax `...` instead. + + > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`. + + ```javascript + // bad + function concatenateAll() { + const args = Array.prototype.slice.call(arguments); + return args.join(''); + } + + // good + function concatenateAll(...args) { + return args.join(''); + } + ``` + + + - Use default parameter syntax rather than mutating function arguments. + + ```javascript + // really bad + function handleThings(opts) { + // No! We shouldn't mutate function arguments. + // Double bad: if opts is falsy it'll be set to an object which may + // be what you want but it can introduce subtle bugs. + opts = opts || {}; + // ... + } + + // still bad + function handleThings(opts) { + if (opts === void 0) { + opts = {}; + } + // ... + } + + // good + function handleThings(opts = {}) { + // ... + } + ``` + + - Avoid side effects with default parameters + + > Why? They are confusing to reason about. + + ```javascript + var b = 1; + // bad + function count(a = b++) { + console.log(a); + } + count(); // 1 + count(); // 2 + count(3); // 3 + count(); // 3 + ``` + + **[⬆ back to top](#table-of-contents)** +## Arrow Functions + + - When you must use function expressions (as when passing an anonymous function), use arrow function notation. + + > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax. + + > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration. + + ```javascript + // bad + [1, 2, 3].map(function (x) { + return x * x; + }); + + // good + [1, 2, 3].map((x) => { + return x * x + }); + ``` + + - If the function body fits on one line, feel free to omit the braces and use implicit return. Otherwise, add the braces and use a `return` statement. + + > Why? Syntactic sugar. It reads well when multiple functions are chained together. + + > Why not? If you plan on returning an object. + + ```javascript + // good + [1, 2, 3].map((x) => x * x); + + // good + [1, 2, 3].map((x) => { + return { number: x }; + }); + ``` + + - Always use parentheses around the arguments. Omitting the parentheses makes the functions less readable and only works for single arguments. + + > Why? These declarations read better with parentheses. They are also required when you have multiple parameters so this enforces consistency. + + ```javascript + // bad + [1, 2, 3].map(x => x * x); + + // good + [1, 2, 3].map((x) => x * x); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Constructors + + - Always use `class`. Avoid manipulating `prototype` directly. + + > Why? `class` syntax is more concise and easier to reason about. + + ```javascript + // bad + function Queue(contents = []) { + this._queue = [...contents]; + } + Queue.prototype.pop = function() { + const value = this._queue[0]; + this._queue.splice(0, 1); + return value; + } + + + // good + class Queue { + constructor(contents = []) { + this._queue = [...contents]; + } + pop() { + const value = this._queue[0]; + this._queue.splice(0, 1); + return value; + } + } + ``` + + - Use `extends` for inheritance. + + > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`. + + ```javascript + // bad + const inherits = require('inherits'); + function PeekableQueue(contents) { + Queue.apply(this, contents); + } + inherits(PeekableQueue, Queue); + PeekableQueue.prototype.peek = function() { + return this._queue[0]; + } + + // good + class PeekableQueue extends Queue { + peek() { + return this._queue[0]; + } + } + ``` + + - 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; + }; + + const luke = new Jedi(); + luke.jump(); // => true + luke.setHeight(20); // => undefined + + // good + class Jedi { + jump() { + this.jumping = true; + return this; + } + + setHeight(height) { + this.height = height; + return this; + } + } + + const 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 + class Jedi { + contructor(options = {}) { + this.name = options.name || 'no name'; + } + + getName() { + return this.name; + } + + toString() { + return `Jedi - ${this.getName()}`; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Modules + + - Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system. + + > Why? Modules are the future, let's start using the future now. + + ```javascript + // bad + const AirbnbStyleGuide = require('./AirbnbStyleGuide'); + module.exports = AirbnbStyleGuide.es6; + + // ok + import AirbnbStyleGuide from './AirbnbStyleGuide'; + export default AirbnbStyleGuide.es6; + + // best + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + + - Do not use wildcard imports. + + > Why? This makes sure you have a single default export. + + ```javascript + // bad + import * as AirbnbStyleGuide from './AirbnbStyleGuide'; + + // good + import AirbnbStyleGuide from './AirbnbStyleGuide'; + ``` + + - And do not export directly from an import. + + > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. + + ```javascript + // bad + // filename es6.js + export { es6 as default } from './airbnbStyleGuide'; + + // good + // filename es6.js + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Iterators and Generators + + - Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. + + > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. + + ```javascript + const numbers = [1, 2, 3, 4, 5]; + + // bad + let sum = 0; + for (let num of numbers) { + sum += num; + } + + sum === 15; + + // good + let sum = 0; + numbers.forEach((num) => sum += num); + sum === 15; + + // best (use the functional force) + const sum = numbers.reduce((total, num) => total + num, 0); + sum === 15; + ``` + + - Don't use generators. + + > Why? They don't transpile well to ES5. + +**[⬆ back to top](#table-of-contents)** ## Properties @@ -325,22 +821,22 @@ - Use dot notation when accessing properties. ```javascript - var luke = { + const luke = { jedi: true, age: 28 }; // bad - var isJedi = luke['jedi']; + const isJedi = luke['jedi']; // good - var isJedi = luke.jedi; + const isJedi = luke.jedi; ``` - Use subscript notation `[]` when accessing properties with a variable. ```javascript - var luke = { + const luke = { jedi: true, age: 28 }; @@ -349,7 +845,7 @@ return luke[prop]; } - var isJedi = getProp('jedi'); + const isJedi = getProp('jedi'); ``` **[⬆ back to top](#table-of-contents)** @@ -357,90 +853,77 @@ ## 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. + - Always use `const` 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(); + const superPower = new SuperPower(); ``` - - Use one `var` declaration per variable. - It's easier to add new variable declarations this way, and you never have - to worry about swapping out a `;` for a `,` or introducing punctuation-only - diffs. + - Use one `const` declaration per variable. + + > Why? It's easier to add new variable declarations this way, and you never have to worry about swapping out a `;` for a `,` or introducing punctuation-only diffs. ```javascript // bad - var items = getItems(), + const items = getItems(), goSportsTeam = true, dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) - var items = getItems(), + const items = getItems(), goSportsTeam = true; dragonball = 'z'; // good - var items = getItems(); - var goSportsTeam = true; - var dragonball = 'z'; + const items = getItems(); + const goSportsTeam = true; + const 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. + - Group all your `const`s and then group all your `let`s. + + > Why? 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, + let i, len, dragonball, items = getItems(), goSportsTeam = true; // bad - var i; - var items = getItems(); - var dragonball; - var goSportsTeam = true; - var len; + let i; + const items = getItems(); + let dragonball; + const goSportsTeam = true; + let len; // good - var items = getItems(); - var goSportsTeam = true; - var dragonball; - var length; - var i; + const goSportsTeam = true; + const items = getItems(); + let dragonball; + let i; + let 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(); + - Assign variables where you need them, but place them in a reasonable place. - if (name === 'test') { - return false; - } - - return name; - } + > Why? `let` and `const` are block scoped and not function scoped. + ```javascript // good function() { - var name = getName(); - test(); console.log('doing stuff..'); //..other stuff.. + const name = getName(); + if (name === 'test') { return false; } @@ -449,10 +932,10 @@ } // bad - unnessary function call - function() { - var name = getName(); + function(hasName) { + const name = getName(); - if (!arguments.length) { + if (!hasName) { return false; } @@ -462,14 +945,12 @@ } // good - function() { - var name; - - if (!arguments.length) { + function(hasName) { + if (!hasName) { return false; } - name = getName(); + const name = getName(); this.setFirstName(name); return true; @@ -481,7 +962,7 @@ ## Hoisting - - Variable declarations get hoisted to the top of their scope, but their assignment does not. + - `var` declarations get hoisted to the top of their scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). It's important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). ```javascript // we know this wouldn't work (assuming there @@ -503,10 +984,17 @@ // declaration to the top of the scope, // which means our example could be rewritten as: function example() { - var declaredButNotAssigned; + let declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; } + + // using const and let + function example() { + console.log(declaredButNotAssigned); // => throws a ReferenceError + console.log(typeof declaredButNotAssigned); // => throws a ReferenceError + const declaredButNotAssigned = true; + } ``` - Anonymous function expressions hoist their variable name, but not the function assignment. @@ -568,7 +1056,6 @@ **[⬆ back to top](#table-of-contents)** - ## Comparison Operators & Equality - Use `===` and `!==` over `==` and `!=`. @@ -707,17 +1194,17 @@ ```javascript // bad - var active = true; // is current tab + const active = true; // is current tab // good // is current tab - var active = true; + const active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' - var type = this._type || 'no type'; + const type = this._type || 'no type'; return type; } @@ -727,7 +1214,7 @@ console.log('fetching type...'); // set the default type to 'no type' - var type = this._type || 'no type'; + const type = this._type || 'no type'; return type; } @@ -769,17 +1256,17 @@ ```javascript // bad function() { - ∙∙∙∙var name; + ∙∙∙∙const name; } // bad function() { - ∙var name; + ∙const name; } // good function() { - ∙∙var name; + ∙∙const name; } ``` @@ -837,10 +1324,10 @@ ```javascript // bad - var x=y+5; + const x=y+5; // good - var x = y + 5; + const x = y + 5; ``` - End files with a single newline character. @@ -891,13 +1378,13 @@ .updateCount(); // bad - var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) + const 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') + const leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') .classed('led', true) @@ -924,7 +1411,7 @@ return baz; // bad - var obj = { + const obj = { foo: function() { }, bar: function() { @@ -933,7 +1420,7 @@ return obj; // good - var obj = { + const obj = { foo: function() { }, @@ -953,21 +1440,21 @@ ```javascript // bad - var story = [ + const story = [ once , upon , aTime ]; // good - var story = [ + const story = [ once, upon, aTime ]; // bad - var hero = { + const hero = { firstName: 'Bob' , lastName: 'Parr' , heroName: 'Mr. Incredible' @@ -975,7 +1462,7 @@ }; // good - var hero = { + const hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', @@ -989,23 +1476,23 @@ ```javascript // bad - var hero = { + const hero = { firstName: 'Kevin', lastName: 'Flynn', }; - var heroes = [ + const heroes = [ 'Batman', 'Superman', ]; // good - var hero = { + const hero = { firstName: 'Kevin', lastName: 'Flynn' }; - var heroes = [ + const heroes = [ 'Batman', 'Superman' ]; @@ -1021,19 +1508,19 @@ ```javascript // bad (function() { - var name = 'Skywalker' + const name = 'Skywalker' return name })() // good - (function() { - var name = 'Skywalker'; + (() => { + const name = 'Skywalker'; return name; })(); // good (guards against the function becoming an argument when two files with IIFEs are concatenated) - ;(function() { - var name = 'Skywalker'; + ;(() => { + const name = 'Skywalker'; return name; })(); ``` @@ -1052,40 +1539,34 @@ // => this.reviewScore = 9; // bad - var totalScore = this.reviewScore + ''; - - // good - var totalScore = '' + this.reviewScore; - - // bad - var totalScore = '' + this.reviewScore + ' total score'; + const totalScore = this.reviewScore + ''; // good - var totalScore = this.reviewScore + ' total score'; + const totalScore = String(this.reviewScore); ``` - Use `parseInt` for Numbers and always with a radix for type casting. ```javascript - var inputValue = '4'; + const inputValue = '4'; // bad - var val = new Number(inputValue); + const val = new Number(inputValue); // bad - var val = +inputValue; + const val = +inputValue; // bad - var val = inputValue >> 0; + const val = inputValue >> 0; // bad - var val = parseInt(inputValue); + const val = parseInt(inputValue); // good - var val = Number(inputValue); + const val = Number(inputValue); // good - var val = parseInt(inputValue, 10); + const 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. @@ -1097,7 +1578,7 @@ * Bitshifting the String to coerce it to a * Number made it a lot faster. */ - var val = inputValue >> 0; + const val = inputValue >> 0; ``` - **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). Largest signed 32-bit Int is 2,147,483,647: @@ -1111,16 +1592,16 @@ - Booleans: ```javascript - var age = 0; + const age = 0; // bad - var hasAge = new Boolean(age); + const hasAge = new Boolean(age); // good - var hasAge = Boolean(age); + const hasAge = Boolean(age); // good - var hasAge = !!age; + const hasAge = !!age; ``` **[⬆ back to top](#table-of-contents)** @@ -1146,13 +1627,12 @@ ```javascript // bad - var OBJEcttsssss = {}; - var this_is_my_object = {}; - var o = {}; + const OBJEcttsssss = {}; + const this_is_my_object = {}; function c() {} // good - var thisIsMyObject = {}; + const thisIsMyObject = {}; function thisIsMyFunction() {} ``` @@ -1164,16 +1644,18 @@ this.name = options.name; } - var bad = new user({ + const bad = new user({ name: 'nope' }); // good - function User(options) { - this.name = options.name; + class User { + constructor(options) { + this.name = options.name; + } } - var good = new User({ + const good = new User({ name: 'yup' }); ``` @@ -1189,69 +1671,73 @@ this._firstName = 'Panda'; ``` - - When saving a reference to `this` use `_this`. + - Don't save references to `this`. Use arrow functions or Function#bind. ```javascript // bad - function() { - var self = this; + function foo() { + const self = this; return function() { console.log(self); }; } // bad - function() { - var that = this; + function foo() { + const that = this; return function() { console.log(that); }; } // good - function() { - var _this = this; - return function() { - console.log(_this); + function foo() { + return () => { + 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); - }; - ``` - - - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. - - If your file exports a single class, your filename should be exactly the name of the class. ```javascript // file contents class CheckBox { // ... } - module.exports = CheckBox; + export default CheckBox; // in some other file // bad - var CheckBox = require('./checkBox'); + import CheckBox from './checkBox'; // bad - var CheckBox = require('./check_box'); + import CheckBox from './check_box'; // good - var CheckBox = require('./CheckBox'); + import CheckBox from './CheckBox'; ``` + - Use camelCase when you export-default a function. Your filename should be identical to your function's name. + + ```javascript + function makeStyleGuide() { + } + + export default makeStyleGuide; + ``` + + - Use PascalCase when you export a singleton / function library / bare object. + + ```javascript + const AirbnbStyleGuide = { + es6: { + } + }; + + export default AirbnbStyleGuide; + ``` + + **[⬆ back to top](#table-of-contents)** @@ -1291,104 +1777,20 @@ - 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]; - }; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## 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'); + class Jedi { + constructor(options = {}) { + const lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); } - }; - - // 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. + set(key, val) { + this[key] = val; + } - ```javascript - function Jedi(options) { - options || (options = {}); - this.name = options.name || 'no name'; + get(key) { + return this[key]; + } } - - Jedi.prototype.getName = function getName() { - return this.name; - }; - - Jedi.prototype.toString = function toString() { - return 'Jedi - ' + this.getName(); - }; ``` **[⬆ back to top](#table-of-contents)** @@ -1398,7 +1800,7 @@ - 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: - ```js + ```javascript // bad $(this).trigger('listingUpdated', listing.id); @@ -1411,7 +1813,7 @@ prefer: - ```js + ```javascript // good $(this).trigger('listingUpdated', { listingId : listing.id }); @@ -1425,47 +1827,16 @@ **[⬆ back to top](#table-of-contents)** -## 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. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) - - 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); - ``` - -**[⬆ back to top](#table-of-contents)** - - ## jQuery - Prefix jQuery object variables with a `$`. ```javascript // bad - var sidebar = $('.sidebar'); + const sidebar = $('.sidebar'); // good - var $sidebar = $('.sidebar'); + const $sidebar = $('.sidebar'); ``` - Cache jQuery lookups. @@ -1484,7 +1855,7 @@ // good function setSidebar() { - var $sidebar = $('.sidebar'); + const $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... @@ -1524,6 +1895,25 @@ **[⬆ back to top](#table-of-contents)** +## ECMAScript 6 Styles + +This is a collection of links to the various es6 features. + +1. [Arrow Functions](#arrow-functions) +1. [Classes](#constructors) +1. [Object Shorthand](#es6-object-shorthand) +1. [Object Concise](#es6-object-concise) +1. [Object Computed Properties](#es6-computed-properties) +1. [Template Strings](#es6-template-literals) +1. [Destructuring](#destructuring) +1. [Default Parameters](#es6-default-parameters) +1. [Rest](#es6-rest) +1. [Array Spreads](#es6-array-spreads) +1. [Let and Const](#references) +1. [Iterators and Generators](#iterators-and-generators) +1. [Modules](#modules) + +**[⬆ back to top](#table-of-contents)** ## Testing @@ -1554,6 +1944,12 @@ ## Resources +**Learning ES6** + + - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html) + - [ExploringJS](http://exploringjs.com/) + - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/) + - [Comprehensive Overview of ES6 Features](http://es6-features.org/) **Read This** @@ -1570,7 +1966,6 @@ - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) - - [JavaScript Standard Style](https://github.com/feross/standard) **Other Styles** @@ -1603,8 +1998,6 @@ - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman - - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke - - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson **Blogs** @@ -1661,7 +2054,6 @@ - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) - - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) diff --git a/es5/README.md b/es5/README.md new file mode 100644 index 0000000000..02ecc75ee6 --- /dev/null +++ b/es5/README.md @@ -0,0 +1,1742 @@ +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +# Airbnb JavaScript Style Guide() { + +*A mostly reasonable approach to JavaScript* + + +## 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. [Comparison Operators & Equality](#comparison-operators--equality) + 1. [Blocks](#blocks) + 1. [Comments](#comments) + 1. [Whitespace](#whitespace) + 1. [Commas](#commas) + 1. [Semicolons](#semicolons) + 1. [Type Casting & Coercion](#type-casting--coercion) + 1. [Naming Conventions](#naming-conventions) + 1. [Accessors](#accessors) + 1. [Constructors](#constructors) + 1. [Events](#events) + 1. [Modules](#modules) + 1. [jQuery](#jquery) + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) + 1. [Testing](#testing) + 1. [Performance](#performance) + 1. [Resources](#resources) + 1. [In the Wild](#in-the-wild) + 1. [Translation](#translation) + 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) + 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) + 1. [Contributors](#contributors) + 1. [License](#license) + +## Types + + - **Primitives**: When you access a primitive type you work directly on its value. + + + `string` + + `number` + + `boolean` + + `null` + + `undefined` + + ```javascript + var foo = 1; + var 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]; + var bar = foo; + + bar[0] = 9; + + console.log(foo[0], bar[0]); // => 9, 9 + ``` + +**[⬆ back to top](#table-of-contents)** + +## Objects + + - Use the literal syntax for object creation. + + ```javascript + // bad + var item = new Object(); + + // good + var item = {}; + ``` + + - 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). + + ```javascript + // bad + var superman = { + default: { clark: 'kent' }, + private: true + }; + + // good + var superman = { + defaults: { clark: 'kent' }, + hidden: true + }; + ``` + + - Use readable synonyms in place of reserved words. + + ```javascript + // bad + var superman = { + class: 'alien' + }; + + // bad + var superman = { + klass: 'alien' + }; + + // good + var superman = { + type: 'alien' + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrays + + - Use the literal syntax for array creation. + + ```javascript + // bad + var items = new Array(); + + // good + var items = []; + ``` + + - Use Array#push instead of direct assignment to add items to an array. + + ```javascript + 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) + + ```javascript + var len = items.length; + var itemsCopy = []; + var i; + + // bad + for (i = 0; i < len; i++) { + itemsCopy[i] = items[i]; + } + + // good + itemsCopy = items.slice(); + ``` + + - To convert an array-like object to an array, use Array#slice. + + ```javascript + function trigger() { + var args = Array.prototype.slice.call(arguments); + ... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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. + - 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). + + ```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 programmatically 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; + var messages; + var length; + var 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 = ''; + } + + // good + function inbox(messages) { + items = []; + + for (i = 0; i < length; i++) { + // use direct assignment in this case because we're micro-optimizing. + items[i] = '
  • ' + messages[i].message + '
  • '; + } + + return ''; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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. + - **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 + // 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. + + ```javascript + // bad + function nope(name, options, arguments) { + // ...stuff... + } + + // good + function yup(name, options, args) { + // ...stuff... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + + +## 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'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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 per variable. + It's easier to add new variable declarations this way, and you never have + to worry about swapping out a `;` for a `,` or introducing punctuation-only + diffs. + + ```javascript + // bad + var items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + 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; + + // bad + var i; + var items = getItems(); + var dragonball; + var goSportsTeam = true; + var len; + + // good + 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() { + 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 - unnessary function call + function() { + var name = getName(); + + if (!arguments.length) { + return false; + } + + this.setFirstName(name); + + return true; + } + + // good + function() { + var name; + + if (!arguments.length) { + return false; + } + + name = getName(); + this.setFirstName(name); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Hoisting + + - Variable declarations get hoisted to the top of their scope, but 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 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; + } + ``` + + - Anonymous function expressions 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/). + +**[⬆ back to top](#table-of-contents)** + + + +## Comparison Operators & Equality + + - Use `===` and `!==` over `==` and `!=`. + - Comparison operators 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** evaluate 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. + +**[⬆ back to top](#table-of-contents)** + + +## 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; + } + ``` + + - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your + `if` block's closing brace. + + ```javascript + // bad + if (test) { + thing1(); + thing2(); + } + else { + thing3(); + } + + // good + if (test) { + thing1(); + thing2(); + } else { + thing3(); + } + ``` + + +**[⬆ back to top](#table-of-contents)** + + +## Comments + + - Use `/** ... */` for multi-line 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 {String} tag + // @return {Element} element + function make(tag) { + + // ...stuff... + + return element; + } + + // good + /** + * make() returns a new element + * based on the passed in tag name + * + * @param {String} tag + * @return {Element} 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 empty line 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; + } + ``` + + - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`. + + - Use `// FIXME:` to annotate problems. + + ```javascript + function Calculator() { + + // FIXME: shouldn't use a global here + total = 0; + + return this; + } + ``` + + - Use `// TODO:` to annotate solutions to problems. + + ```javascript + function Calculator() { + + // TODO: total should be configurable by an options param + this.total = 0; + + return this; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. + + ```javascript + // bad + if(isJedi) { + fight (); + } + + // good + if (isJedi) { + fight(); + } + + // bad + function fight () { + console.log ('Swooosh!'); + } + + // good + function fight() { + console.log('Swooosh!'); + } + ``` + + - Set off operators with spaces. + + ```javascript + // bad + var x=y+5; + + // good + var x = y + 5; + ``` + + - End files with a single newline character. + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this); + ``` + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this);↵ + ↵ + ``` + + ```javascript + // good + (function(global) { + // ...stuff... + })(this);↵ + ``` + + - Use indentation when making long method chains. Use a leading dot, which + emphasizes that the line is a method call, not a new statement. + + ```javascript + // bad + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // 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').classed('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') + .classed('led', true) + .attr('width', (radius + margin) * 2) + .append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); + ``` + + - Leave a blank line after blocks and before the next statement + + ```javascript + // bad + if (foo) { + return bar; + } + return baz; + + // good + if (foo) { + return bar; + } + + return baz; + + // bad + var obj = { + foo: function() { + }, + bar: function() { + } + }; + return obj; + + // good + var obj = { + foo: function() { + }, + + bar: function() { + } + }; + + return obj; + ``` + + +**[⬆ back to top](#table-of-contents)** + +## Commas + + - Leading commas: **Nope.** + + ```javascript + // bad + var story = [ + once + , upon + , aTime + ]; + + // good + var story = [ + 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](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. + + ```javascript + // bad + var hero = { + firstName: 'Kevin', + lastName: 'Flynn', + }; + + var heroes = [ + 'Batman', + 'Superman', + ]; + + // good + var hero = { + firstName: 'Kevin', + lastName: 'Flynn' + }; + + var heroes = [ + 'Batman', + 'Superman' + ]; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Semicolons + + - **Yup.** + + ```javascript + // 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; + })(); + ``` + + [Read more](http://stackoverflow.com/a/7365214/1712802). + +**[⬆ back to top](#table-of-contents)** + + +## 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. + + ```javascript + 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. + + ```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; + ``` + + - **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). Largest signed 32-bit Int is 2,147,483,647: + + ```javascript + 2147483647 >> 0 //=> 2147483647 + 2147483648 >> 0 //=> -2147483648 + 2147483649 >> 0 //=> -2147483647 + ``` + + - Booleans: + + ```javascript + var age = 0; + + // bad + var hasAge = new Boolean(age); + + // good + var hasAge = Boolean(age); + + // good + var hasAge = !!age; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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 o = {}; + function c() {} + + // good + var thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` + + - 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); + }; + ``` + + - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. + + - If your file exports a single class, your filename should be exactly the name of the class. + ```javascript + // file contents + class CheckBox { + // ... + } + module.exports = CheckBox; + + // in some other file + // bad + var CheckBox = require('./checkBox'); + + // bad + var CheckBox = require('./check_box'); + + // good + var CheckBox = require('./CheckBox'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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]; + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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(); + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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: + + ```js + // bad + $(this).trigger('listingUpdated', listing.id); + + ... + + $(this).on('listingUpdated', function(e, listingId) { + // do something with listingId + }); + ``` + + prefer: + + ```js + // good + $(this).trigger('listingUpdated', { listingId : listing.id }); + + ... + + $(this).on('listingUpdated', function(e, data) { + // do something with data.listingId + }); + ``` + + **[⬆ back to top](#table-of-contents)** + + +## 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. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) + - 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); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## 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 + $('ul', '.sidebar').hide(); + + // bad + $('.sidebar').find('ul').hide(); + + // good + $('.sidebar ul').hide(); + + // good + $('.sidebar > ul').hide(); + + // good + $sidebar.find('ul').hide(); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## ECMAScript 5 Compatibility + + - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). + +**[⬆ back to top](#table-of-contents)** + + +## Testing + + - **Yup.** + + ```javascript + function() { + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Performance + + - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) + - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) + - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) + - [Bang Function](http://jsperf.com/bang-function) + - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) + - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) + - [Long String Concatenation](http://jsperf.com/ya-string-concat) + - Loading... + +**[⬆ back to top](#table-of-contents)** + + +## Resources + + +**Read This** + + - [Annotated ECMAScript 5.1](http://es5.github.com/) + +**Tools** + + - Code Style Linters + + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) + + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) + +**Other Styleguides** + + - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) + - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) + - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) + - [JavaScript Standard Style](https://github.com/feross/standard) + +**Other Styles** + + - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen + - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen + - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun + - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman + +**Further Reading** + + - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll + - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer + - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz + - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban + - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock + +**Books** + + - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford + - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov + - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz + - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders + - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas + - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw + - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig + - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch + - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault + - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg + - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy + - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon + - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov + - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman + - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke + - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson + +**Blogs** + + - [DailyJS](http://dailyjs.com/) + - [JavaScript Weekly](http://javascriptweekly.com/) + - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) + - [Bocoup Weblog](http://weblog.bocoup.com/) + - [Adequately Good](http://www.adequatelygood.com/) + - [NCZOnline](http://www.nczonline.net/) + - [Perfection Kills](http://perfectionkills.com/) + - [Ben Alman](http://benalman.com/) + - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) + - [Dustin Diaz](http://dustindiaz.com/) + - [nettuts](http://net.tutsplus.com/?s=javascript) + +**Podcasts** + + - [JavaScript Jabber](http://devchat.tv/js-jabber/) + + +**[⬆ back to top](#table-of-contents)** + +## In the Wild + + This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. + + - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) + - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) + - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) + - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript) + - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) + - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) + - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) + - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) + - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) + - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) + - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) + - **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) + - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) + - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) + - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) + - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) + - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) + - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) + - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) + - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) + - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) + - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) + - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) + - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) + - **Muber**: [muber/javascript](https://github.com/muber/javascript) + - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) + - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) + - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) + - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) + - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) + - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) + - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) + - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) + - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) + - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) + - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) + - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) + - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) + - **Target**: [target/javascript](https://github.com/target/javascript) + - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) + - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) + - **Userify**: [userify/javascript](https://github.com/userify/javascript) + - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) + - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) + - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) + - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) + +## Translation + + This style guide is also available in other languages: + + - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) + - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) + - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) + - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [adamlu/javascript-style-guide](https://github.com/adamlu/javascript-style-guide) + - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) + - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) + - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) + - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) + - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) + - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + +## The JavaScript Style Guide Guide + + - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) + +## Chat With Us About JavaScript + + - Find us on [gitter](https://gitter.im/airbnb/javascript). + +## Contributors + + - [View Contributors](https://github.com/airbnb/javascript/graphs/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. + +**[⬆ back to top](#table-of-contents)** + +# }; diff --git a/linters/jshintrc b/linters/jshintrc index cc6e398b40..141067fd23 100644 --- a/linters/jshintrc +++ b/linters/jshintrc @@ -13,6 +13,9 @@ // Define globals exposed by Node.js. "node": true, + // Allow ES6. + "esnext": true, + /* * ENFORCING OPTIONS * =================