From 58cdc731f435db78f3c1f4d466284796128fb75b Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Thu, 2 Apr 2015 08:43:50 -0700 Subject: [PATCH 01/17] Initial ES6 style guide --- README.md | 1085 +++++++++++++++++++++---------- es5/README.md | 1712 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 2445 insertions(+), 352 deletions(-) create mode 100644 es5/README.md diff --git a/README.md b/README.md index 02ecc75ee6..c6b552c885 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,11 @@ 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 +57,8 @@ + `undefined` ```javascript - var foo = 1; - var bar = foo; + const foo = 1; + let bar = foo; bar = 9; @@ -64,8 +71,8 @@ + `function` ```javascript - var foo = [1, 2]; - var bar = foo; + const foo = [1, 2]; + const bar = foo; bar[0] = 9; @@ -74,29 +81,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 +161,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 +281,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,33 +300,96 @@ 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]; + + // bad + const first = arr[0]; + const second = arr[1]; + + // 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 + 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 + 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 @@ -182,16 +397,16 @@ ```javascript // bad - var name = "Bob Parr"; + const name = "Bob Parr"; // good - var name = 'Bob Parr'; + const name = 'Bob Parr'; // bad - var fullName = "Bob " + this.lastName; + const fullName = "Bob " + this.lastName; // good - var fullName = 'Bob ' + this.lastName; + const fullName = 'Bob ' + this.lastName; ``` - Strings longer than 80 characters should be written across multiple lines using string concatenation. @@ -199,62 +414,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 +455,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 +490,9 @@ } // good - var test; + let test; if (currentUser) { - test = function test() { + test = () => { console.log('Yup.'); }; } @@ -316,31 +512,320 @@ } ``` + + - 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 = {}) { + // ... + } + ``` + +**[⬆ 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 default { es6 } 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 function constructors 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 === 10; + + // good + let sum = 0; + numbers.forEach((num) => sum += num); + sum === 10; + + // best (use the functional force) + const sum = numbers.reduce((total, num) => total + num, 0); + sum === 10; + ``` + + - Don't use generators. + + > Why? They don't transpile well to ES5. + +**[⬆ back to top](#table-of-contents)** + ## Properties - 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 +834,7 @@ return luke[prop]; } - var isJedi = getProp('jedi'); + const isJedi = getProp('jedi'); ``` **[⬆ back to top](#table-of-contents)** @@ -357,90 +842,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; + let items = getItems(); + let dragonball; + let 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. + - Assign variables where you need them, but place them in a reasonable place. - ```javascript - // bad - function() { - test(); - console.log('doing stuff..'); - - //..other stuff.. - - var name = getName(); - - 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 +921,10 @@ } // bad - unnessary function call - function() { - var name = getName(); + function(hasName) { + const name = getName(); - if (!arguments.length) { + if (!hasName) { return false; } @@ -462,14 +934,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 +951,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, but their assignment does not. `const` and `let` declarations suffer from [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). Also see 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 +973,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. @@ -517,7 +994,7 @@ anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { + let anonymous = function() { console.log('anonymous function expression'); }; } @@ -533,7 +1010,7 @@ superPower(); // => ReferenceError superPower is not defined - var named = function superPower() { + let named = function superPower() { console.log('Flying'); }; } @@ -545,7 +1022,7 @@ named(); // => TypeError named is not a function - var named = function named() { + let named = function named() { console.log('named'); } } @@ -568,7 +1045,6 @@ **[⬆ back to top](#table-of-contents)** - ## Comparison Operators & Equality - Use `===` and `!==` over `==` and `!=`. @@ -707,17 +1183,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 +1203,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 +1245,17 @@ ```javascript // bad function() { - ∙∙∙∙var name; + ∙∙∙∙const name; } // bad function() { - ∙var name; + ∙const name; } // good function() { - ∙∙var name; + ∙∙const name; } ``` @@ -837,10 +1313,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 +1367,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 +1400,7 @@ return baz; // bad - var obj = { + const obj = { foo: function() { }, bar: function() { @@ -933,7 +1409,7 @@ return obj; // good - var obj = { + const obj = { foo: function() { }, @@ -953,21 +1429,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 +1451,7 @@ }; // good - var hero = { + const hero = { firstName: 'Bob', lastName: 'Parr', heroName: 'Mr. Incredible', @@ -989,23 +1465,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 +1497,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 +1528,40 @@ // => this.reviewScore = 9; // bad - var totalScore = this.reviewScore + ''; + const totalScore = this.reviewScore + ''; // good - var totalScore = '' + this.reviewScore; + const totalScore = '' + this.reviewScore; // bad - var totalScore = '' + this.reviewScore + ' total score'; + const totalScore = '' + this.reviewScore + ' total score'; // good - var totalScore = this.reviewScore + ' total score'; + const totalScore = this.reviewScore + ' total score'; ``` - 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 +1573,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 +1587,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 +1622,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 +1639,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,50 +1666,33 @@ 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 @@ -1243,15 +1703,36 @@ // in some other file // bad - var CheckBox = require('./checkBox'); + const CheckBox = require('./checkBox'); // bad - var CheckBox = require('./check_box'); + const CheckBox = require('./check_box'); // good - var CheckBox = require('./CheckBox'); + const CheckBox = require('./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 +1772,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 +1795,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 +1808,7 @@ prefer: - ```js + ```javascript // good $(this).trigger('listingUpdated', { listingId : listing.id }); @@ -1425,47 +1822,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 +1850,7 @@ // good function setSidebar() { - var $sidebar = $('.sidebar'); + const $sidebar = $('.sidebar'); $sidebar.hide(); // ...stuff... @@ -1524,6 +1890,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 @@ -1570,7 +1955,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 +1987,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 +2043,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..bcbe6489c3 --- /dev/null +++ b/es5/README.md @@ -0,0 +1,1712 @@ +[![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 = []; + ``` + + - If you don't know array length use Array#push. + + ```javascript + var someStack = []; + + + // bad + someStack[someStack.length] = 'abracadabra'; + + // good + someStack.push('abracadabra'); + ``` + + - When you need to copy an array use Array#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++) { + 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 + function() { + var name = getName(); + + if (!arguments.length) { + return false; + } + + return true; + } + + // good + function() { + if (!arguments.length) { + return false; + } + + var name = getName(); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Hoisting + + - Variable declarations get hoisted to the top of their scope, their assignment does not. + + ```javascript + // we know this wouldn't work (assuming there + // is no notDefined global variable) + function example() { + console.log(notDefined); // => throws a ReferenceError + } + + // creating a variable declaration after you + // reference the variable will work due to + // variable hoisting. Note: the assignment + // value of `true` is not hoisted. + function example() { + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; + } + + // The 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 multiline comments. Include a description, specify types and values for all parameters and return values. + + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {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' + }); + ``` + + - 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').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); + ``` + + - 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 = {}; + function c() {} + var u = new user({ + name: 'Bob Parr' + }); + + // good + var thisIsMyObject = {}; + function thisIsMyFunction() {} + var user = new User({ + name: 'Bob Parr' + }); + ``` + + - Use PascalCase when naming constructors or classes. + + ```javascript + // bad + function user(options) { + this.name = options.name; + } + + var bad = new user({ + name: 'nope' + }); + + // good + function User(options) { + this.name = options.name; + } + + var good = new User({ + name: 'yup' + }); + ``` + + - Use a leading underscore `_` when naming private properties. + + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + + // good + this._firstName = 'Panda'; + ``` + + - When saving a reference to `this` use `_this`. + + ```javascript + // bad + function() { + var self = this; + return function() { + console.log(self); + }; + } + + // bad + function() { + var that = this; + return function() { + console.log(that); + }; + } + + // good + function() { + var _this = this; + return function() { + console.log(_this); + }; + } + ``` + + - Name your functions. This is helpful for stack traces. + + ```javascript + // bad + var log = function(msg) { + console.log(msg); + }; + + // good + var log = function log(msg) { + console.log(msg); + }; + ``` + + - **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) + - **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) + - **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) + - **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: + + - ![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) + - ![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) + - ![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) + - ![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) + - ![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) + - ![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) + - ![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) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![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) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + +## 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)** + +# }; From b8fd0438fb2878aaf617716ac3513ae3da6910c6 Mon Sep 17 00:00:00 2001 From: Casey Jenks Date: Thu, 2 Apr 2015 21:41:11 -0400 Subject: [PATCH 02/17] Iterators and Generators: sum should be 15, not 10 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c6b552c885..896351e0a7 100644 --- a/README.md +++ b/README.md @@ -786,16 +786,16 @@ sum += num; } - sum === 10; + sum === 15; // good let sum = 0; numbers.forEach((num) => sum += num); - sum === 10; + sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); - sum === 10; + sum === 15; ``` - Don't use generators. From a6a573e3ccac39cabf83780a0b02b30a2c5ee6b2 Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Fri, 3 Apr 2015 14:47:01 -0700 Subject: [PATCH 03/17] Use more template literals, s/suffer/blessed with --- README.md | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 896351e0a7..fbb05387fa 100644 --- a/README.md +++ b/README.md @@ -401,12 +401,6 @@ // good const name = 'Bob Parr'; - - // bad - const fullName = "Bob " + this.lastName; - - // good - const fullName = 'Bob ' + this.lastName; ``` - Strings longer than 80 characters should be written across multiple lines using string concatenation. @@ -714,7 +708,7 @@ } toString() { - return 'Jedi - ' + this.getName(); + return `Jedi - ${this.getName()}`; } } ``` @@ -951,7 +945,7 @@ ## Hoisting - - `var` declarations get hoisted to the top of their scope, but their assignment does not. `const` and `let` declarations suffer from [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). Also see why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15). + - `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 @@ -1531,13 +1525,7 @@ const totalScore = this.reviewScore + ''; // good - const totalScore = '' + this.reviewScore; - - // bad - const totalScore = '' + this.reviewScore + ' total score'; - - // good - const totalScore = this.reviewScore + ' total score'; + const totalScore = String(this.reviewScore); ``` - Use `parseInt` for Numbers and always with a radix for type casting. From 22e3c89d045e60fba240b07009bed07ba1797eaf Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Fri, 3 Apr 2015 15:15:56 -0700 Subject: [PATCH 04/17] Removing a few trailing commas --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fbb05387fa..eb77894051 100644 --- a/README.md +++ b/README.md @@ -198,7 +198,7 @@ const obj = { id: 5, name: 'San Francisco', - [getKey('enabled')]: true, + [getKey('enabled')]: true }; ``` @@ -212,7 +212,7 @@ addValue: function (value) { return atom.value + value; - }, + } }; // good @@ -221,7 +221,7 @@ addValue(value) { return atom.value + value; - }, + } }; ``` From bc5b0ee007ba9e7bd92afb7caf325f4c63fc6e09 Mon Sep 17 00:00:00 2001 From: Luke Westby Date: Fri, 3 Apr 2015 21:13:50 -0500 Subject: [PATCH 05/17] Change wording in Iterators and Generators I found the term "function constructors" to be confusing as the functions the section refers to are not constructors. I think "higher-order functions" or something similar would be more clear. Thanks! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb77894051..f68fc1d4de 100644 --- a/README.md +++ b/README.md @@ -767,7 +767,7 @@ ## Iterators and Generators - - Don't use iterators. Prefer JavaScript's function constructors instead of loops like `for-of`. + - 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. From e8260674988be12080b3c75d3af84c64ed35af86 Mon Sep 17 00:00:00 2001 From: NoNameSheep Date: Sat, 4 Apr 2015 13:54:49 +0800 Subject: [PATCH 06/17] advice against side effect in default parameter --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index f68fc1d4de..869f8a051c 100644 --- a/README.md +++ b/README.md @@ -550,6 +550,23 @@ // ... } ``` + + - Don't put side effect into default parameter + + > it introduces confusion and subtlety. Arguments in function call are evaluated at call site, but default parameters are not evaluated at define site. + + ```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)** From 38ae6b6df209d229491cb6ce0edc2c0d5b1d34b9 Mon Sep 17 00:00:00 2001 From: Sean Massa Date: Sun, 5 Apr 2015 01:34:31 -0500 Subject: [PATCH 07/17] add `bad` comment to bad section of destructuring --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 869f8a051c..db16779168 100644 --- a/README.md +++ b/README.md @@ -370,6 +370,7 @@ > Why? You can add new properties over time or change the order of things without breaking call sites. ```javascript + // bad function processInput(input) { // then a miracle occurs return [left, right, top, bottom]; From 6d34c516cc1649fe795a5145e89545328d04d360 Mon Sep 17 00:00:00 2001 From: Harrison Shoff Date: Sun, 5 Apr 2015 21:49:13 -0700 Subject: [PATCH 08/17] [toc] remove extra modules link --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index db16779168..272d94a140 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ 1. [Naming Conventions](#naming-conventions) 1. [Accessors](#accessors) 1. [Events](#events) - 1. [Modules](#modules) 1. [jQuery](#jquery) 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) 1. [ECMAScript 6 Styles](#ecmascript-6-styles) From f7321b303d6f3046ba49741041312fa2d8c76ed7 Mon Sep 17 00:00:00 2001 From: Harrison Shoff Date: Sun, 5 Apr 2015 21:50:08 -0700 Subject: [PATCH 09/17] [modules] fix invalid syntax in bad example. fixes #287 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 272d94a140..24a5edcfbe 100644 --- a/README.md +++ b/README.md @@ -772,7 +772,7 @@ ```javascript // bad // filename es6.js - export default { es6 } from './airbnbStyleGuide'; + export { es6 as default } from './airbnbStyleGuide'; // good // filename es6.js From 875d2ad05e7587bec304375f9d5451a80ef13ae5 Mon Sep 17 00:00:00 2001 From: Tomek Wiszniewski Date: Fri, 10 Apr 2015 00:13:09 +0200 Subject: [PATCH 10/17] Add `esnext` to the jsHint configuration This way we'll allow ES6 syntax. --- linters/jshintrc | 3 +++ 1 file changed, 3 insertions(+) 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 * ================= From ee176044c303a523cbb1ee68d1202d399639bcb3 Mon Sep 17 00:00:00 2001 From: dsc Date: Fri, 10 Apr 2015 15:34:54 +0200 Subject: [PATCH 11/17] Rename two let keywords to const --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 24a5edcfbe..0c1afab917 100644 --- a/README.md +++ b/README.md @@ -897,9 +897,9 @@ // bad let i; - let items = getItems(); + const items = getItems(); let dragonball; - let goSportsTeam = true; + const goSportsTeam = true; let len; // good From 0cca5e21fc66d6c5f076af71ab9a269a3ccddcc7 Mon Sep 17 00:00:00 2001 From: Tomek Wiszniewski Date: Sat, 11 Apr 2015 12:46:08 +0200 Subject: [PATCH 12/17] Fix hoisting examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hoisting only happens to `var`. As kangax describes in [Why `typeof` is no longer “safe”](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15/3). Also, I wonder if we need the whole section, since you recommend to [avoid using `var` altogether](https://github.com/airbnb/javascript/blob/b492/README.md#references). --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0c1afab917..aaf2290f9e 100644 --- a/README.md +++ b/README.md @@ -1005,7 +1005,7 @@ anonymous(); // => TypeError anonymous is not a function - let anonymous = function() { + var anonymous = function() { console.log('anonymous function expression'); }; } @@ -1021,7 +1021,7 @@ superPower(); // => ReferenceError superPower is not defined - let named = function superPower() { + var named = function superPower() { console.log('Flying'); }; } @@ -1033,7 +1033,7 @@ named(); // => TypeError named is not a function - let named = function named() { + var named = function named() { console.log('named'); } } From e5006931f106fd6b1e3907fddc70950ed6c1cff2 Mon Sep 17 00:00:00 2001 From: Matias Singers Date: Sun, 12 Apr 2015 20:44:48 +0800 Subject: [PATCH 13/17] Use modules in naming conventions example Following the rule from further up: "Always use modules (import/export) over a non-standard module system." --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index aaf2290f9e..1ba0446bdc 100644 --- a/README.md +++ b/README.md @@ -1704,17 +1704,17 @@ class CheckBox { // ... } - module.exports = CheckBox; + export default CheckBox; // in some other file // bad - const CheckBox = require('./checkBox'); + import CheckBox from './checkBox'; // bad - const CheckBox = require('./check_box'); + import CheckBox from './check_box'; // good - const 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. From d0028724eac28637d7bc4cde2ceac1c634dc452c Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Mon, 13 Apr 2015 09:04:39 +0800 Subject: [PATCH 14/17] add semicolons --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1ba0446bdc..b149f3570e 100644 --- a/README.md +++ b/README.md @@ -550,21 +550,21 @@ // ... } ``` - + - Don't put side effect into default parameter - - > it introduces confusion and subtlety. Arguments in function call are evaluated at call site, but default parameters are not evaluated at define site. + + > it introduces confusion and subtlety. Arguments in function call are evaluated at call site, but default parameters are not evaluated at define site. ```javascript - var b = 1 + var b = 1; // bad function count(a = b++) { - console.log(a) + console.log(a); } - count() // 1 - count() // 2 - count(3) // 3 - count() // 3 + count(); // 1 + count(); // 2 + count(3); // 3 + count(); // 3 ``` From cb47b478c70bb0d1bee0a60643c5970bd67a799a Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Mon, 27 Apr 2015 16:58:09 -0700 Subject: [PATCH 15/17] Amend grammar for default parameters --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b149f3570e..e63ee40032 100644 --- a/README.md +++ b/README.md @@ -551,9 +551,9 @@ } ``` - - Don't put side effect into default parameter + - Avoid side effects with default parameters - > it introduces confusion and subtlety. Arguments in function call are evaluated at call site, but default parameters are not evaluated at define site. + > Why? They are confusing to reason about. ```javascript var b = 1; From 455529c2346bd9f38e9ce09c507afbc11bba6b17 Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Tue, 28 Apr 2015 21:28:40 -0700 Subject: [PATCH 16/17] Updates es5 guide with latest --- es5/README.md | 78 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/es5/README.md b/es5/README.md index bcbe6489c3..02ecc75ee6 100644 --- a/es5/README.md +++ b/es5/README.md @@ -135,7 +135,7 @@ var items = []; ``` - - If you don't know array length use Array#push. + - Use Array#push instead of direct assignment to add items to an array. ```javascript var someStack = []; @@ -250,6 +250,7 @@ items = []; for (i = 0; i < length; i++) { + // use direct assignment in this case because we're micro-optimizing. items[i] = '
  • ' + messages[i].message + '
  • '; } @@ -301,7 +302,7 @@ } ``` - - Never name a parameter `arguments`, this will take precedence over the `arguments` object that is given to every function scope. + - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. ```javascript // bad @@ -447,7 +448,7 @@ return name; } - // bad + // bad - unnessary function call function() { var name = getName(); @@ -455,16 +456,21 @@ return false; } + this.setFirstName(name); + return true; } // good function() { + var name; + if (!arguments.length) { return false; } - var name = getName(); + name = getName(); + this.setFirstName(name); return true; } @@ -475,7 +481,7 @@ ## Hoisting - - Variable declarations get hoisted to the top of their scope, their assignment does not. + - Variable declarations get hoisted to the top of their scope, but their assignment does not. ```javascript // we know this wouldn't work (assuming there @@ -665,7 +671,7 @@ ## Comments - - Use `/** ... */` for multiline comments. Include a description, specify types and values for all parameters and return values. + - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. ```javascript // bad @@ -803,6 +809,30 @@ }); ``` + - 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 @@ -846,7 +876,7 @@ // bad $('#items'). - find('selected'). + find('.selected'). highlight(). end(). find('.open'). @@ -861,8 +891,8 @@ .updateCount(); // bad - var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) - .attr('width', (radius + margin) * 2).append('svg:g') + 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); @@ -870,8 +900,8 @@ var leds = stage.selectAll('.led') .data(data) .enter().append('svg:svg') - .class('led', true) - .attr('width', (radius + margin) * 2) + .classed('led', true) + .attr('width', (radius + margin) * 2) .append('svg:g') .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') .call(tron.led); @@ -1118,17 +1148,12 @@ // bad var OBJEcttsssss = {}; var this_is_my_object = {}; + var o = {}; 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. @@ -1607,6 +1632,7 @@ 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) @@ -1616,6 +1642,7 @@ - **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) @@ -1624,6 +1651,7 @@ - **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) @@ -1656,18 +1684,20 @@ This style guide is also available in other languages: - - ![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) - - ![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) - ![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) - - ![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) - - ![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) - ![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) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![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) + - ![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 From cc460132ccbcbad2dceac70474ca3756e43b5b95 Mon Sep 17 00:00:00 2001 From: Josh Perez Date: Tue, 28 Apr 2015 21:31:58 -0700 Subject: [PATCH 17/17] Learn you some ES6 --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index e63ee40032..5c1913cc55 100644 --- a/README.md +++ b/README.md @@ -1944,6 +1944,12 @@ This is a collection of links to the various es6 features. ## 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**