From 714e1428cc00256167b74e3fce2ff9dad80c673b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 26 Oct 2015 10:12:44 +0100 Subject: [PATCH 001/143] Write introduction and approach section --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fdcdccae2b..c95fbfc734 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,20 @@ -# Airbnb JavaScript Style Guide() { +# ~~Airbnb~~ ascribe JavaScript Style Guide() { -*A mostly reasonable approach to JavaScript* +## Introduction +At ascribe we write a lot of JavaScript and value quality code. +Since all of us liked [Airbnb's JavaScript Style Guide](https://github.com/airbnb/javascript), we figured that we can just fork it and change it to our needs. + +## Approach +As we want everyone in the team to be able to take part in the creation of this style guide, we decided to have it reviewed and transformed to our specific needs. +This is why we're going to remove all the contents of this document, to add them bit-by-bit again through a process of pull-requests and reviews. +Depending on how fast the review will be, every other day there will be a pull a new pull request for everyone to read and comment on. + +As for adjusting the linters, we still need to figure out a way on how to change them efficiently. So if you have suggestions, come forward. -[![Downloads](https://img.shields.io/npm/dm/eslint-config-airbnb.svg)](https://www.npmjs.com/package/eslint-config-airbnb) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Other Style Guides - [ES5](es5/) - [React](react/) - - [CSS & Sass](https://github.com/airbnb/css) - - [Ruby](https://github.com/airbnb/ruby) ## Table of Contents From a62dc6b3765dc83c367a56946b8e66cd29b0dce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 26 Oct 2015 10:19:40 +0100 Subject: [PATCH 002/143] Move original style guides to *-backup.md files --- README-backup.md | 2254 +++++++++++++++++++++++++++++++++++++++ README.md | 2272 +--------------------------------------- es5/README-backup.md | 1742 ++++++++++++++++++++++++++++++ es5/README.md | 1706 +----------------------------- react/README-backup.md | 315 ++++++ react/README.md | 324 +----- 6 files changed, 4365 insertions(+), 4248 deletions(-) create mode 100644 README-backup.md create mode 100644 es5/README-backup.md create mode 100644 react/README-backup.md diff --git a/README-backup.md b/README-backup.md new file mode 100644 index 0000000000..c95fbfc734 --- /dev/null +++ b/README-backup.md @@ -0,0 +1,2254 @@ +# ~~Airbnb~~ ascribe JavaScript Style Guide() { + +## Introduction +At ascribe we write a lot of JavaScript and value quality code. +Since all of us liked [Airbnb's JavaScript Style Guide](https://github.com/airbnb/javascript), we figured that we can just fork it and change it to our needs. + +## Approach +As we want everyone in the team to be able to take part in the creation of this style guide, we decided to have it reviewed and transformed to our specific needs. +This is why we're going to remove all the contents of this document, to add them bit-by-bit again through a process of pull-requests and reviews. +Depending on how fast the review will be, every other day there will be a pull a new pull request for everyone to read and comment on. + +As for adjusting the linters, we still need to figure out a way on how to change them efficiently. So if you have suggestions, come forward. + + +Other Style Guides + - [ES5](es5/) + - [React](react/) + +## 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) + 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. [Events](#events) + 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) + 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 + + - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. + + + `string` + + `number` + + `boolean` + + `null` + + `undefined` + + ```javascript + const foo = 1; + let bar = foo; + + bar = 9; + + console.log(foo, bar); // => 1, 9 + ``` + - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. + + + `object` + + `array` + + `function` + + ```javascript + const foo = [1, 2]; + const bar = foo; + + bar[0] = 9; + + console.log(foo[0], bar[0]); // => 9, 9 + ``` + +**[⬆ back to top](#table-of-contents)** + +## References + + - [2.1](#2.1) 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; + ``` + + - [2.2](#2.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; + } + ``` + + - [2.3](#2.3) 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 + + - [3.1](#3.1) Use the literal syntax for object creation. + + ```javascript + // bad + const item = new Object(); + + // good + const item = {}; + ``` + + - [3.2](#3.2) If your code will be executed in browsers in script context, 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). It’s OK to use them in ES6 modules and server-side code. + + ```javascript + // bad + const superman = { + default: { clark: 'kent' }, + private: true, + }; + + // good + const superman = { + defaults: { clark: 'kent' }, + hidden: true, + }; + ``` + + - [3.3](#3.3) Use readable synonyms in place of reserved words. + + ```javascript + // bad + const superman = { + class: 'alien', + }; + + // bad + const superman = { + klass: 'alien', + }; + + // good + const superman = { + type: 'alien', + }; + ``` + + + - [3.4](#3.4) 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, + }; + ``` + + + - [3.5](#3.5) 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; + }, + }; + ``` + + + - [3.6](#3.6) 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, + }; + ``` + + - [3.7](#3.7) 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, + twoJediWalkIntoACantina: 2, + lukeSkywalker, + episodeThree: 3, + mayTheFourth: 4, + anakinSkywalker, + }; + + // good + const obj = { + lukeSkywalker, + anakinSkywalker, + episodeOne: 1, + twoJediWalkIntoACantina: 2, + episodeThree: 3, + mayTheFourth: 4, + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrays + + - [4.1](#4.1) Use the literal syntax for array creation. + + ```javascript + // bad + const items = new Array(); + + // good + const items = []; + ``` + + - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. + + ```javascript + const someStack = []; + + // bad + someStack[someStack.length] = 'abracadabra'; + + // good + someStack.push('abracadabra'); + ``` + + + - [4.3](#4.3) Use array spreads `...` to copy arrays. + + ```javascript + // bad + const len = items.length; + const itemsCopy = []; + let i; + + for (i = 0; i < len; i++) { + itemsCopy[i] = items[i]; + } + + // good + const itemsCopy = [...items]; + ``` + - [4.4](#4.4) To convert an array-like object to an array, use Array#from. + + ```javascript + const foo = document.querySelectorAll('.foo'); + const nodes = Array.from(foo); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Destructuring + + - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. + + > Why? Destructuring saves you from creating temporary references for those properties. + + ```javascript + // 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}`; + } + ``` + + - [5.2](#5.2) Use array destructuring. + + ```javascript + const arr = [1, 2, 3, 4]; + + // bad + const first = arr[0]; + const second = arr[1]; + + // good + const [first, second] = arr; + ``` + + - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. + + > Why? You can add new properties over time or change the order of things without breaking call sites. + + ```javascript + // bad + 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 + + - [6.1](#6.1) Use single quotes `''` for strings. + + ```javascript + // bad + const name = "Capt. Janeway"; + + // good + const name = 'Capt. Janeway'; + ``` + + - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. + - [6.3](#6.3) 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 + 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 + 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 + 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.'; + ``` + + + - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. + + > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. + + ```javascript + // bad + function sayHi(name) { + return 'How are you, ' + name + '?'; + } + + // bad + function sayHi(name) { + return ['How are you, ', name, '?'].join(); + } + + // good + function sayHi(name) { + return `How are you, ${name}?`; + } + ``` + - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. + +**[⬆ back to top](#table-of-contents)** + + +## Functions + + - [7.1](#7.1) 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 + // bad + const foo = function () { + }; + + // good + function foo() { + } + ``` + + - [7.2](#7.2) Function expressions: + + ```javascript + // immediately-invoked function expression (IIFE) + (() => { + console.log('Welcome to the Internet. Please follow me.'); + })(); + ``` + + - [7.3](#7.3) 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. + - [7.4](#7.4) **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 + let test; + if (currentUser) { + test = () => { + console.log('Yup.'); + }; + } + ``` + + - [7.5](#7.5) 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... + } + ``` + + + - [7.6](#7.6) 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(''); + } + ``` + + + - [7.7](#7.7) 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 = {}) { + // ... + } + ``` + + - [7.8](#7.8) Avoid side effects with default parameters. + + > Why? They are confusing to reason about. + + ```javascript + var b = 1; + // bad + function count(a = b++) { + console.log(a); + } + count(); // 1 + count(); // 2 + count(3); // 3 + count(); // 3 + ``` + + - [7.9](#7.9) Always put default parameters last. + + ```javascript + // bad + function handleThings(opts = {}, name) { + // ... + } + + // good + function handleThings(name, opts = {}) { + // ... + } + ``` + +- [7.10](#7.10) Never use the Function constructor to create a new function. + + > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. + + ```javascript + // bad + var add = new Function('a', 'b', 'return a + b'); + + // still bad + var subtract = Function('a', 'b', 'return a - b'); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrow Functions + + - [8.1](#8.1) 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) { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + ``` + + - [8.2](#8.2) If the function body consists of a single expression, feel free to omit the braces and use the implicit return. Otherwise 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(number => `A string containing the ${number}.`); + + // bad + [1, 2, 3].map(number => { + const nextNumber = number + 1; + `A string containing the ${nextNumber}.`; + }); + + // good + [1, 2, 3].map(number => { + const nextNumber = number + 1; + return `A string containing the ${nextNumber}.`; + }); + ``` + + - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. + + > Why? It shows clearly where the function starts and ends. + + ```js + // bad + [1, 2, 3].map(number => 'As time went by, the string containing the ' + + `${number} became much longer. So we needed to break it over multiple ` + + 'lines.' + ); + + // good + [1, 2, 3].map(number => ( + `As time went by, the string containing the ${number} became much ` + + 'longer. So we needed to break it over multiple lines.' + )); + ``` + + + - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses. + + > Why? Less visual clutter. + + ```js + // good + [1, 2, 3].map(x => x * x); + + // good + [1, 2, 3].reduce((y, x) => x + y); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Constructors + + - [9.1](#9.1) 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; + } + } + ``` + + - [9.2](#9.2) 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]; + } + } + ``` + + - [9.3](#9.3) 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); + ``` + + + - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + + ```javascript + class Jedi { + constructor(options = {}) { + this.name = options.name || 'no name'; + } + + getName() { + return this.name; + } + + toString() { + return `Jedi - ${this.getName()}`; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Modules + + - [10.1](#10.1) 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; + ``` + + - [10.2](#10.2) 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'; + ``` + + - [10.3](#10.3) And do not export directly from an import. + + > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. + + ```javascript + // bad + // filename es6.js + export { es6 as default } from './airbnbStyleGuide'; + + // good + // filename es6.js + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Iterators and Generators + + - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. + + > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. + + ```javascript + const numbers = [1, 2, 3, 4, 5]; + + // bad + let sum = 0; + for (let num of numbers) { + sum += num; + } + + sum === 15; + + // good + let sum = 0; + numbers.forEach((num) => sum += num); + sum === 15; + + // best (use the functional force) + const sum = numbers.reduce((total, num) => total + num, 0); + sum === 15; + ``` + + - [11.2](#11.2) Don't use generators for now. + + > Why? They don't transpile well to ES5. + +**[⬆ back to top](#table-of-contents)** + + +## Properties + + - [12.1](#12.1) Use dot notation when accessing properties. + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + // bad + const isJedi = luke['jedi']; + + // good + const isJedi = luke.jedi; + ``` + + - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + function getProp(prop) { + return luke[prop]; + } + + const isJedi = getProp('jedi'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Variables + + - [13.1](#13.1) 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 + const superPower = new SuperPower(); + ``` + + - [13.2](#13.2) 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 + const items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + const items = getItems(), + goSportsTeam = true; + dragonball = 'z'; + + // good + const items = getItems(); + const goSportsTeam = true; + const dragonball = 'z'; + ``` + + - [13.3](#13.3) 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 + let i, len, dragonball, + items = getItems(), + goSportsTeam = true; + + // bad + let i; + const items = getItems(); + let dragonball; + const goSportsTeam = true; + let len; + + // good + const goSportsTeam = true; + const items = getItems(); + let dragonball; + let i; + let length; + ``` + + - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. + + > Why? `let` and `const` are block scoped and not function scoped. + + ```javascript + // good + function() { + test(); + console.log('doing stuff..'); + + //..other stuff.. + + const name = getName(); + + if (name === 'test') { + return false; + } + + return name; + } + + // bad - unnecessary function call + function(hasName) { + const name = getName(); + + if (!hasName) { + return false; + } + + this.setFirstName(name); + + return true; + } + + // good + function(hasName) { + if (!hasName) { + return false; + } + + const name = getName(); + this.setFirstName(name); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Hoisting + + - [14.1](#14.1) `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 + // 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() { + 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; + } + ``` + + - [14.2](#14.2) 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'); + }; + } + ``` + + - [14.3](#14.3) 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'); + } + } + ``` + + - [14.4](#14.4) 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 + + - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. + - [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract 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 + } + ``` + + - [15.3](#15.3) Use shortcuts. + + ```javascript + // bad + if (name !== '') { + // ...stuff... + } + + // good + if (name) { + // ...stuff... + } + + // bad + if (collection.length > 0) { + // ...stuff... + } + + // good + if (collection.length) { + // ...stuff... + } + ``` + + - [15.4](#15.4) 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 + + - [16.1](#16.1) 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; + } + ``` + + - [16.2](#16.2) 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 + + - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {String} tag + // @return {Element} element + function make(tag) { + + // ...stuff... + + return element; + } + + // good + /** + * make() returns a new element + * based on the passed in tag name + * + * @param {String} tag + * @return {Element} element + */ + function make(tag) { + + // ...stuff... + + return element; + } + ``` + + - [17.2](#17.2) 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 + const active = true; // is current tab + + // good + // is current tab + const active = true; + + // bad + function getType() { + console.log('fetching type...'); + // set the default type to 'no type' + const type = this._type || 'no type'; + + return type; + } + + // good + function getType() { + console.log('fetching type...'); + + // set the default type to 'no type' + const type = this._type || 'no type'; + + return type; + } + ``` + + - [17.3](#17.3) 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`. + + - [17.4](#17.4) Use `// FIXME:` to annotate problems. + + ```javascript + class Calculator extends Abacus { + constructor() { + super(); + + // FIXME: shouldn't use a global here + total = 0; + } + } + ``` + + - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. + + ```javascript + class Calculator extends Abacus { + constructor() { + super(); + + // TODO: total should be configurable by an options param + this.total = 0; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Whitespace + + - [18.1](#18.1) Use soft tabs set to 2 spaces. + + ```javascript + // bad + function() { + ∙∙∙∙const name; + } + + // bad + function() { + ∙const name; + } + + // good + function() { + ∙∙const name; + } + ``` + + - [18.2](#18.2) 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', + }); + ``` + + - [18.3](#18.3) 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!'); + } + ``` + + - [18.4](#18.4) Set off operators with spaces. + + ```javascript + // bad + const x=y+5; + + // good + const x = y + 5; + ``` + + - [18.5](#18.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);↵ + ``` + + - [18.6](#18.6) 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 + 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 + const 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); + ``` + + - [18.7](#18.7) 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 + const obj = { + foo() { + }, + bar() { + }, + }; + return obj; + + // good + const obj = { + foo() { + }, + + bar() { + }, + }; + + return obj; + + // bad + const arr = [ + function foo() { + }, + function bar() { + }, + ]; + return arr; + + // good + const arr = [ + function foo() { + }, + + function bar() { + }, + ]; + + return arr; + ``` + + +**[⬆ back to top](#table-of-contents)** + +## Commas + + - [19.1](#19.1) Leading commas: **Nope.** + + ```javascript + // bad + const story = [ + once + , upon + , aTime + ]; + + // good + const story = [ + once, + upon, + aTime, + ]; + + // bad + const hero = { + firstName: 'Ada' + , lastName: 'Lovelace' + , birthYear: 1815 + , superPower: 'computers' + }; + + // good + const hero = { + firstName: 'Ada', + lastName: 'Lovelace', + birthYear: 1815, + superPower: 'computers', + }; + ``` + + - [19.2](#19.2) Additional trailing comma: **Yup.** + + > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers. + + ```javascript + // bad - git diff without trailing comma + const hero = { + firstName: 'Florence', + - lastName: 'Nightingale' + + lastName: 'Nightingale', + + inventorOf: ['coxcomb graph', 'modern nursing'] + }; + + // good - git diff with trailing comma + const hero = { + firstName: 'Florence', + lastName: 'Nightingale', + + inventorOf: ['coxcomb chart', 'modern nursing'], + }; + + // bad + const hero = { + firstName: 'Dana', + lastName: 'Scully' + }; + + const heroes = [ + 'Batman', + 'Superman' + ]; + + // good + const hero = { + firstName: 'Dana', + lastName: 'Scully', + }; + + const heroes = [ + 'Batman', + 'Superman', + ]; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Semicolons + + - [20.1](#20.1) **Yup.** + + ```javascript + // bad + (function() { + const name = 'Skywalker' + return name + })() + + // good + (() => { + const name = 'Skywalker'; + return name; + })(); + + // good (guards against the function becoming an argument when two files with IIFEs are concatenated) + ;(() => { + const name = 'Skywalker'; + return name; + })(); + ``` + + [Read more](http://stackoverflow.com/a/7365214/1712802). + +**[⬆ back to top](#table-of-contents)** + + +## Type Casting & Coercion + + - [21.1](#21.1) Perform type coercion at the beginning of the statement. + - [21.2](#21.2) Strings: + + ```javascript + // => this.reviewScore = 9; + + // bad + const totalScore = this.reviewScore + ''; + + // good + const totalScore = String(this.reviewScore); + ``` + + - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. + + ```javascript + const inputValue = '4'; + + // bad + const val = new Number(inputValue); + + // bad + const val = +inputValue; + + // bad + const val = inputValue >> 0; + + // bad + const val = parseInt(inputValue); + + // good + const val = Number(inputValue); + + // good + const val = parseInt(inputValue, 10); + ``` + + - [21.4](#21.4) 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. + */ + const val = inputValue >> 0; + ``` + + - [21.5](#21.5) **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 + ``` + + - [21.6](#21.6) Booleans: + + ```javascript + const age = 0; + + // bad + const hasAge = new Boolean(age); + + // good + const hasAge = Boolean(age); + + // good + const hasAge = !!age; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Naming Conventions + + - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. + + ```javascript + // bad + function q() { + // ...stuff... + } + + // good + function query() { + // ..stuff.. + } + ``` + + - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. + + ```javascript + // bad + const OBJEcttsssss = {}; + const this_is_my_object = {}; + function c() {} + + // good + const thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` + + - [22.3](#22.3) Use PascalCase when naming constructors or classes. + + ```javascript + // bad + function user(options) { + this.name = options.name; + } + + const bad = new user({ + name: 'nope', + }); + + // good + class User { + constructor(options) { + this.name = options.name; + } + } + + const good = new User({ + name: 'yup', + }); + ``` + + - [22.4](#22.4) Use a leading underscore `_` when naming private properties. + + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + + // good + this._firstName = 'Panda'; + ``` + + - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. + + ```javascript + // bad + function foo() { + const self = this; + return function() { + console.log(self); + }; + } + + // bad + function foo() { + const that = this; + return function() { + console.log(that); + }; + } + + // good + function foo() { + return () => { + console.log(this); + }; + } + ``` + + - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. + ```javascript + // file contents + class CheckBox { + // ... + } + export default CheckBox; + + // in some other file + // bad + import CheckBox from './checkBox'; + + // bad + import CheckBox from './check_box'; + + // good + import CheckBox from './CheckBox'; + ``` + + - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. + + ```javascript + function makeStyleGuide() { + } + + export default makeStyleGuide; + ``` + + - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. + + ```javascript + const AirbnbStyleGuide = { + es6: { + } + }; + + export default AirbnbStyleGuide; + ``` + + +**[⬆ back to top](#table-of-contents)** + + +## Accessors + + - [23.1](#23.1) Accessor functions for properties are not required. + - [23.2](#23.2) 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); + ``` + + - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. + + ```javascript + // bad + if (!dragon.age()) { + return false; + } + + // good + if (!dragon.hasAge()) { + return false; + } + ``` + + - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. + + ```javascript + class Jedi { + constructor(options = {}) { + const lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); + } + + set(key, val) { + this[key] = val; + } + + get(key) { + return this[key]; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Events + + - [24.1](#24.1) 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: + + ```javascript + // bad + $(this).trigger('listingUpdated', listing.id); + + ... + + $(this).on('listingUpdated', function(e, listingId) { + // do something with listingId + }); + ``` + + prefer: + + ```javascript + // good + $(this).trigger('listingUpdated', { listingId: listing.id }); + + ... + + $(this).on('listingUpdated', function(e, data) { + // do something with data.listingId + }); + ``` + + **[⬆ back to top](#table-of-contents)** + + +## jQuery + + - [25.1](#25.1) Prefix jQuery object variables with a `$`. + + ```javascript + // bad + const sidebar = $('.sidebar'); + + // good + const $sidebar = $('.sidebar'); + + // good + const $sidebarBtn = $('.sidebar-btn'); + ``` + + - [25.2](#25.2) Cache jQuery lookups. + + ```javascript + // bad + function setSidebar() { + $('.sidebar').hide(); + + // ...stuff... + + $('.sidebar').css({ + 'background-color': 'pink' + }); + } + + // good + function setSidebar() { + const $sidebar = $('.sidebar'); + $sidebar.hide(); + + // ...stuff... + + $sidebar.css({ + 'background-color': 'pink' + }); + } + ``` + + - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + - [25.4](#25.4) 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 + + - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). + +**[⬆ back to top](#table-of-contents)** + +## ECMAScript 6 Styles + + - [27.1](#27.1) 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 + + - [28.1](#28.1) **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 + +**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** + + - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) + +**Tools** + + - Code Style Linters + + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) + + [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 Style Guides** + + - [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/) + +**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: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - 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 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) + - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) + - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) + - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/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) + - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) + - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) + - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) + - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) + - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) + - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) + - **General Electric**: [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) + - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) + - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) + - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) + - **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) + - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/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) + - **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) + - **Springload**: [springload/javascript](https://github.com/springload/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) + - **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) + +**[⬆ back to top](#table-of-contents)** + +## Translation + + This style guide is also available in other languages: + + - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) + - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) + - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/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) + - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) + - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) + - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) + - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) + - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) + - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + +## The JavaScript Style Guide Guide + + - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) + +## Chat With Us About JavaScript + + - Find us on [gitter](https://gitter.im/airbnb/javascript). + +## Contributors + + - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) + + +## License + +(The MIT License) + +Copyright (c) 2014 Airbnb + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**[⬆ back to top](#table-of-contents)** + +## Amendments + +We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. + +# }; diff --git a/README.md b/README.md index c95fbfc734..8a62dc6e54 100644 --- a/README.md +++ b/README.md @@ -18,2237 +18,41 @@ Other Style Guides ## 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) - 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. [Events](#events) - 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) - 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 - - - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. - - + `string` - + `number` - + `boolean` - + `null` - + `undefined` - - ```javascript - const foo = 1; - let bar = foo; - - bar = 9; - - console.log(foo, bar); // => 1, 9 - ``` - - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. - - + `object` - + `array` - + `function` - - ```javascript - const foo = [1, 2]; - const bar = foo; - - bar[0] = 9; - - console.log(foo[0], bar[0]); // => 9, 9 - ``` - -**[⬆ back to top](#table-of-contents)** - -## References - - - [2.1](#2.1) 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; - ``` - - - [2.2](#2.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; - } - ``` - - - [2.3](#2.3) 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 - - - [3.1](#3.1) Use the literal syntax for object creation. - - ```javascript - // bad - const item = new Object(); - - // good - const item = {}; - ``` - - - [3.2](#3.2) If your code will be executed in browsers in script context, 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). It’s OK to use them in ES6 modules and server-side code. - - ```javascript - // bad - const superman = { - default: { clark: 'kent' }, - private: true, - }; - - // good - const superman = { - defaults: { clark: 'kent' }, - hidden: true, - }; - ``` - - - [3.3](#3.3) Use readable synonyms in place of reserved words. - - ```javascript - // bad - const superman = { - class: 'alien', - }; - - // bad - const superman = { - klass: 'alien', - }; - - // good - const superman = { - type: 'alien', - }; - ``` - - - - [3.4](#3.4) 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, - }; - ``` - - - - [3.5](#3.5) 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; - }, - }; - ``` - - - - [3.6](#3.6) 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, - }; - ``` - - - [3.7](#3.7) 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, - twoJediWalkIntoACantina: 2, - lukeSkywalker, - episodeThree: 3, - mayTheFourth: 4, - anakinSkywalker, - }; - - // good - const obj = { - lukeSkywalker, - anakinSkywalker, - episodeOne: 1, - twoJediWalkIntoACantina: 2, - episodeThree: 3, - mayTheFourth: 4, - }; - ``` - -**[⬆ back to top](#table-of-contents)** - -## Arrays - - - [4.1](#4.1) Use the literal syntax for array creation. - - ```javascript - // bad - const items = new Array(); - - // good - const items = []; - ``` - - - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. - - ```javascript - const someStack = []; - - // bad - someStack[someStack.length] = 'abracadabra'; - - // good - someStack.push('abracadabra'); - ``` - - - - [4.3](#4.3) Use array spreads `...` to copy arrays. - - ```javascript - // bad - const len = items.length; - const itemsCopy = []; - let i; - - for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; - } - - // good - const itemsCopy = [...items]; - ``` - - [4.4](#4.4) To convert an array-like object to an array, use Array#from. - - ```javascript - const foo = document.querySelectorAll('.foo'); - const nodes = Array.from(foo); - ``` - -**[⬆ back to top](#table-of-contents)** - -## Destructuring - - - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. - - > Why? Destructuring saves you from creating temporary references for those properties. - - ```javascript - // 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}`; - } - ``` - - - [5.2](#5.2) Use array destructuring. - - ```javascript - const arr = [1, 2, 3, 4]; - - // bad - const first = arr[0]; - const second = arr[1]; - - // good - const [first, second] = arr; - ``` - - - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. - - > Why? You can add new properties over time or change the order of things without breaking call sites. - - ```javascript - // bad - 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 - - - [6.1](#6.1) Use single quotes `''` for strings. - - ```javascript - // bad - const name = "Capt. Janeway"; - - // good - const name = 'Capt. Janeway'; - ``` - - - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. - - [6.3](#6.3) 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 - 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 - 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 - 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.'; - ``` - - - - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. - - > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. - - ```javascript - // bad - function sayHi(name) { - return 'How are you, ' + name + '?'; - } - - // bad - function sayHi(name) { - return ['How are you, ', name, '?'].join(); - } - - // good - function sayHi(name) { - return `How are you, ${name}?`; - } - ``` - - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. - -**[⬆ back to top](#table-of-contents)** - - -## Functions - - - [7.1](#7.1) 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 - // bad - const foo = function () { - }; - - // good - function foo() { - } - ``` - - - [7.2](#7.2) Function expressions: - - ```javascript - // immediately-invoked function expression (IIFE) - (() => { - console.log('Welcome to the Internet. Please follow me.'); - })(); - ``` - - - [7.3](#7.3) 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. - - [7.4](#7.4) **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 - let test; - if (currentUser) { - test = () => { - console.log('Yup.'); - }; - } - ``` - - - [7.5](#7.5) 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... - } - ``` - - - - [7.6](#7.6) 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(''); - } - ``` - - - - [7.7](#7.7) 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 = {}) { - // ... - } - ``` - - - [7.8](#7.8) Avoid side effects with default parameters. - - > Why? They are confusing to reason about. - - ```javascript - var b = 1; - // bad - function count(a = b++) { - console.log(a); - } - count(); // 1 - count(); // 2 - count(3); // 3 - count(); // 3 - ``` - - - [7.9](#7.9) Always put default parameters last. - - ```javascript - // bad - function handleThings(opts = {}, name) { - // ... - } - - // good - function handleThings(name, opts = {}) { - // ... - } - ``` - -- [7.10](#7.10) Never use the Function constructor to create a new function. - - > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. - - ```javascript - // bad - var add = new Function('a', 'b', 'return a + b'); - - // still bad - var subtract = Function('a', 'b', 'return a - b'); - ``` - -**[⬆ back to top](#table-of-contents)** - -## Arrow Functions - - - [8.1](#8.1) 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) { - const y = x + 1; - return x * y; - }); - - // good - [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; - }); - ``` - - - [8.2](#8.2) If the function body consists of a single expression, feel free to omit the braces and use the implicit return. Otherwise 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(number => `A string containing the ${number}.`); - - // bad - [1, 2, 3].map(number => { - const nextNumber = number + 1; - `A string containing the ${nextNumber}.`; - }); - - // good - [1, 2, 3].map(number => { - const nextNumber = number + 1; - return `A string containing the ${nextNumber}.`; - }); - ``` - - - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. - - > Why? It shows clearly where the function starts and ends. - - ```js - // bad - [1, 2, 3].map(number => 'As time went by, the string containing the ' + - `${number} became much longer. So we needed to break it over multiple ` + - 'lines.' - ); - - // good - [1, 2, 3].map(number => ( - `As time went by, the string containing the ${number} became much ` + - 'longer. So we needed to break it over multiple lines.' - )); - ``` - - - - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses. - - > Why? Less visual clutter. - - ```js - // good - [1, 2, 3].map(x => x * x); - - // good - [1, 2, 3].reduce((y, x) => x + y); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Constructors - - - [9.1](#9.1) 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; - } - } - ``` - - - [9.2](#9.2) 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]; - } - } - ``` - - - [9.3](#9.3) 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); - ``` - - - - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. - - ```javascript - class Jedi { - constructor(options = {}) { - this.name = options.name || 'no name'; - } - - getName() { - return this.name; - } - - toString() { - return `Jedi - ${this.getName()}`; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Modules - - - [10.1](#10.1) 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; - ``` - - - [10.2](#10.2) 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'; - ``` - - - [10.3](#10.3) And do not export directly from an import. - - > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. - - ```javascript - // bad - // filename es6.js - export { es6 as default } from './airbnbStyleGuide'; - - // good - // filename es6.js - import { es6 } from './AirbnbStyleGuide'; - export default es6; - ``` - -**[⬆ back to top](#table-of-contents)** - -## Iterators and Generators - - - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. - - > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. - - ```javascript - const numbers = [1, 2, 3, 4, 5]; - - // bad - let sum = 0; - for (let num of numbers) { - sum += num; - } - - sum === 15; - - // good - let sum = 0; - numbers.forEach((num) => sum += num); - sum === 15; - - // best (use the functional force) - const sum = numbers.reduce((total, num) => total + num, 0); - sum === 15; - ``` - - - [11.2](#11.2) Don't use generators for now. - - > Why? They don't transpile well to ES5. - -**[⬆ back to top](#table-of-contents)** - - -## Properties - - - [12.1](#12.1) Use dot notation when accessing properties. - - ```javascript - const luke = { - jedi: true, - age: 28, - }; - - // bad - const isJedi = luke['jedi']; - - // good - const isJedi = luke.jedi; - ``` - - - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. - - ```javascript - const luke = { - jedi: true, - age: 28, - }; - - function getProp(prop) { - return luke[prop]; - } - - const isJedi = getProp('jedi'); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Variables - - - [13.1](#13.1) 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 - const superPower = new SuperPower(); - ``` - - - [13.2](#13.2) 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 - const items = getItems(), - goSportsTeam = true, - dragonball = 'z'; - - // bad - // (compare to above, and try to spot the mistake) - const items = getItems(), - goSportsTeam = true; - dragonball = 'z'; - - // good - const items = getItems(); - const goSportsTeam = true; - const dragonball = 'z'; - ``` - - - [13.3](#13.3) 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 - let i, len, dragonball, - items = getItems(), - goSportsTeam = true; - - // bad - let i; - const items = getItems(); - let dragonball; - const goSportsTeam = true; - let len; - - // good - const goSportsTeam = true; - const items = getItems(); - let dragonball; - let i; - let length; - ``` - - - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. - - > Why? `let` and `const` are block scoped and not function scoped. - - ```javascript - // good - function() { - test(); - console.log('doing stuff..'); - - //..other stuff.. - - const name = getName(); - - if (name === 'test') { - return false; - } - - return name; - } - - // bad - unnecessary function call - function(hasName) { - const name = getName(); - - if (!hasName) { - return false; - } - - this.setFirstName(name); - - return true; - } - - // good - function(hasName) { - if (!hasName) { - return false; - } - - const name = getName(); - this.setFirstName(name); - - return true; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Hoisting - - - [14.1](#14.1) `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 - // 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() { - 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; - } - ``` - - - [14.2](#14.2) 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'); - }; - } - ``` - - - [14.3](#14.3) 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'); - } - } - ``` - - - [14.4](#14.4) 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 - - - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. - - [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract 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 - } - ``` - - - [15.3](#15.3) Use shortcuts. - - ```javascript - // bad - if (name !== '') { - // ...stuff... - } - - // good - if (name) { - // ...stuff... - } - - // bad - if (collection.length > 0) { - // ...stuff... - } - - // good - if (collection.length) { - // ...stuff... - } - ``` - - - [15.4](#15.4) 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 - - - [16.1](#16.1) 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; - } - ``` - - - [16.2](#16.2) 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 - - - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. - - ```javascript - // bad - // make() returns a new element - // based on the passed in tag name - // - // @param {String} tag - // @return {Element} element - function make(tag) { - - // ...stuff... - - return element; - } - - // good - /** - * make() returns a new element - * based on the passed in tag name - * - * @param {String} tag - * @return {Element} element - */ - function make(tag) { - - // ...stuff... - - return element; - } - ``` - - - [17.2](#17.2) 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 - const active = true; // is current tab - - // good - // is current tab - const active = true; - - // bad - function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - const type = this._type || 'no type'; - - return type; - } - - // good - function getType() { - console.log('fetching type...'); - - // set the default type to 'no type' - const type = this._type || 'no type'; - - return type; - } - ``` - - - [17.3](#17.3) 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`. - - - [17.4](#17.4) Use `// FIXME:` to annotate problems. - - ```javascript - class Calculator extends Abacus { - constructor() { - super(); - - // FIXME: shouldn't use a global here - total = 0; - } - } - ``` - - - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. - - ```javascript - class Calculator extends Abacus { - constructor() { - super(); - - // TODO: total should be configurable by an options param - this.total = 0; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Whitespace - - - [18.1](#18.1) Use soft tabs set to 2 spaces. - - ```javascript - // bad - function() { - ∙∙∙∙const name; - } - - // bad - function() { - ∙const name; - } - - // good - function() { - ∙∙const name; - } - ``` - - - [18.2](#18.2) 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', - }); - ``` - - - [18.3](#18.3) 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!'); - } - ``` - - - [18.4](#18.4) Set off operators with spaces. - - ```javascript - // bad - const x=y+5; - - // good - const x = y + 5; - ``` - - - [18.5](#18.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);↵ - ``` - - - [18.6](#18.6) 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 - 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 - const 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); - ``` - - - [18.7](#18.7) 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 - const obj = { - foo() { - }, - bar() { - }, - }; - return obj; - - // good - const obj = { - foo() { - }, - - bar() { - }, - }; - - return obj; - - // bad - const arr = [ - function foo() { - }, - function bar() { - }, - ]; - return arr; - - // good - const arr = [ - function foo() { - }, - - function bar() { - }, - ]; - - return arr; - ``` - - -**[⬆ back to top](#table-of-contents)** - -## Commas - - - [19.1](#19.1) Leading commas: **Nope.** - - ```javascript - // bad - const story = [ - once - , upon - , aTime - ]; - - // good - const story = [ - once, - upon, - aTime, - ]; - - // bad - const hero = { - firstName: 'Ada' - , lastName: 'Lovelace' - , birthYear: 1815 - , superPower: 'computers' - }; - - // good - const hero = { - firstName: 'Ada', - lastName: 'Lovelace', - birthYear: 1815, - superPower: 'computers', - }; - ``` - - - [19.2](#19.2) Additional trailing comma: **Yup.** - - > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers. - - ```javascript - // bad - git diff without trailing comma - const hero = { - firstName: 'Florence', - - lastName: 'Nightingale' - + lastName: 'Nightingale', - + inventorOf: ['coxcomb graph', 'modern nursing'] - }; - - // good - git diff with trailing comma - const hero = { - firstName: 'Florence', - lastName: 'Nightingale', - + inventorOf: ['coxcomb chart', 'modern nursing'], - }; - - // bad - const hero = { - firstName: 'Dana', - lastName: 'Scully' - }; - - const heroes = [ - 'Batman', - 'Superman' - ]; - - // good - const hero = { - firstName: 'Dana', - lastName: 'Scully', - }; - - const heroes = [ - 'Batman', - 'Superman', - ]; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Semicolons - - - [20.1](#20.1) **Yup.** - - ```javascript - // bad - (function() { - const name = 'Skywalker' - return name - })() - - // good - (() => { - const name = 'Skywalker'; - return name; - })(); - - // good (guards against the function becoming an argument when two files with IIFEs are concatenated) - ;(() => { - const name = 'Skywalker'; - return name; - })(); - ``` - - [Read more](http://stackoverflow.com/a/7365214/1712802). - -**[⬆ back to top](#table-of-contents)** - - -## Type Casting & Coercion - - - [21.1](#21.1) Perform type coercion at the beginning of the statement. - - [21.2](#21.2) Strings: - - ```javascript - // => this.reviewScore = 9; - - // bad - const totalScore = this.reviewScore + ''; - - // good - const totalScore = String(this.reviewScore); - ``` - - - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. - - ```javascript - const inputValue = '4'; - - // bad - const val = new Number(inputValue); - - // bad - const val = +inputValue; - - // bad - const val = inputValue >> 0; - - // bad - const val = parseInt(inputValue); - - // good - const val = Number(inputValue); - - // good - const val = parseInt(inputValue, 10); - ``` - - - [21.4](#21.4) 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. - */ - const val = inputValue >> 0; - ``` - - - [21.5](#21.5) **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 - ``` - - - [21.6](#21.6) Booleans: - - ```javascript - const age = 0; - - // bad - const hasAge = new Boolean(age); - - // good - const hasAge = Boolean(age); - - // good - const hasAge = !!age; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Naming Conventions - - - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. - - ```javascript - // bad - function q() { - // ...stuff... - } - - // good - function query() { - // ..stuff.. - } - ``` - - - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. - - ```javascript - // bad - const OBJEcttsssss = {}; - const this_is_my_object = {}; - function c() {} - - // good - const thisIsMyObject = {}; - function thisIsMyFunction() {} - ``` - - - [22.3](#22.3) Use PascalCase when naming constructors or classes. - - ```javascript - // bad - function user(options) { - this.name = options.name; - } - - const bad = new user({ - name: 'nope', - }); - - // good - class User { - constructor(options) { - this.name = options.name; - } - } - - const good = new User({ - name: 'yup', - }); - ``` - - - [22.4](#22.4) Use a leading underscore `_` when naming private properties. - - ```javascript - // bad - this.__firstName__ = 'Panda'; - this.firstName_ = 'Panda'; - - // good - this._firstName = 'Panda'; - ``` - - - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. - - ```javascript - // bad - function foo() { - const self = this; - return function() { - console.log(self); - }; - } - - // bad - function foo() { - const that = this; - return function() { - console.log(that); - }; - } - - // good - function foo() { - return () => { - console.log(this); - }; - } - ``` - - - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. - ```javascript - // file contents - class CheckBox { - // ... - } - export default CheckBox; - - // in some other file - // bad - import CheckBox from './checkBox'; - - // bad - import CheckBox from './check_box'; - - // good - import CheckBox from './CheckBox'; - ``` - - - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. - - ```javascript - function makeStyleGuide() { - } - - export default makeStyleGuide; - ``` - - - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. - - ```javascript - const AirbnbStyleGuide = { - es6: { - } - }; - - export default AirbnbStyleGuide; - ``` - - -**[⬆ back to top](#table-of-contents)** - - -## Accessors - - - [23.1](#23.1) Accessor functions for properties are not required. - - [23.2](#23.2) 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); - ``` - - - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. - - ```javascript - // bad - if (!dragon.age()) { - return false; - } - - // good - if (!dragon.hasAge()) { - return false; - } - ``` - - - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. - - ```javascript - class Jedi { - constructor(options = {}) { - const lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); - } - - set(key, val) { - this[key] = val; - } - - get(key) { - return this[key]; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Events - - - [24.1](#24.1) 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: - - ```javascript - // bad - $(this).trigger('listingUpdated', listing.id); - - ... - - $(this).on('listingUpdated', function(e, listingId) { - // do something with listingId - }); - ``` - - prefer: - - ```javascript - // good - $(this).trigger('listingUpdated', { listingId: listing.id }); - - ... - - $(this).on('listingUpdated', function(e, data) { - // do something with data.listingId - }); - ``` - - **[⬆ back to top](#table-of-contents)** - - -## jQuery - - - [25.1](#25.1) Prefix jQuery object variables with a `$`. - - ```javascript - // bad - const sidebar = $('.sidebar'); - - // good - const $sidebar = $('.sidebar'); - - // good - const $sidebarBtn = $('.sidebar-btn'); - ``` - - - [25.2](#25.2) Cache jQuery lookups. - - ```javascript - // bad - function setSidebar() { - $('.sidebar').hide(); - - // ...stuff... - - $('.sidebar').css({ - 'background-color': 'pink' - }); - } - - // good - function setSidebar() { - const $sidebar = $('.sidebar'); - $sidebar.hide(); - - // ...stuff... - - $sidebar.css({ - 'background-color': 'pink' - }); - } - ``` - - - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - [25.4](#25.4) 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 - - - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). - -**[⬆ back to top](#table-of-contents)** - -## ECMAScript 6 Styles - - - [27.1](#27.1) 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 - - - [28.1](#28.1) **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 - -**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** - - - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) - -**Tools** - - - Code Style Linters - + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) - + [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 Style Guides** - - - [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/) - -**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: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - 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 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) - - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) - - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) - - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/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) - - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) - - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) - - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) - - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) - - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) - - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) - - **General Electric**: [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) - - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) - - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) - - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) - - **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) - - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/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) - - **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) - - **Springload**: [springload/javascript](https://github.com/springload/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) - - **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) - -**[⬆ back to top](#table-of-contents)** - -## Translation - - This style guide is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) - - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) - - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/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) - - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - -## Chat With Us About JavaScript - - - Find us on [gitter](https://gitter.im/airbnb/javascript). - -## Contributors - - - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) - - -## License - -(The MIT License) - -Copyright (c) 2014 Airbnb - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -**[⬆ back to top](#table-of-contents)** - -## Amendments - -We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. - -# }; + 1. [Types](#types) #TBD + 1. [References](#references) #TBD + 1. [Objects](#objects) #TBD + 1. [Arrays](#arrays) #TBD + 1. [Destructuring](#destructuring) #TBD + 1. [Strings](#strings) #TBD + 1. [Functions](#functions) #TBD + 1. [Arrow Functions](#arrow-functions) #TBD + 1. [Constructors](#constructors) #TBD + 1. [Modules](#modules) #TBD + 1. [Iterators and Generators](#iterators-and-generators) #TBD + 1. [Properties](#properties) #TBD + 1. [Variables](#variables) #TBD + 1. [Hoisting](#hoisting) #TBD + 1. [Comparison Operators & Equality](#comparison-operators--equality) #TBD + 1. [Blocks](#blocks) #TBD + 1. [Comments](#comments) #TBD + 1. [Whitespace](#whitespace) #TBD + 1. [Commas](#commas) #TBD + 1. [Semicolons](#semicolons) #TBD + 1. [Type Casting & Coercion](#type-casting--coercion) #TBD + 1. [Naming Conventions](#naming-conventions) #TBD + 1. [Accessors](#accessors) #TBD + 1. [Events](#events) #TBD + 1. [jQuery](#jquery) #TBD + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) #TBD #TBD + 1. [ECMAScript 6 Styles](#ecmascript-6-styles) #TBD + 1. [Testing](#testing) #TBD + 1. [Performance](#performance) #TBD + 1. [Resources](#resources) #TBD + 1. [In the Wild](#in-the-wild) #TBD + 1. [Translation](#translation) #TBD + 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) #TBD + 1. [Chat With Us About JavaScript](#chat-with-us-about-javascript) #TBD + 1. [Contributors](#contributors) #TBD + 1. [License](#license) #TBD + +# } diff --git a/es5/README-backup.md b/es5/README-backup.md new file mode 100644 index 0000000000..2d24f1a4a2 --- /dev/null +++ b/es5/README-backup.md @@ -0,0 +1,1742 @@ +[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +# Airbnb JavaScript Style Guide() { + +*A mostly reasonable approach to JavaScript* + + +## Table of Contents + + 1. [Types](#types) + 1. [Objects](#objects) + 1. [Arrays](#arrays) + 1. [Strings](#strings) + 1. [Functions](#functions) + 1. [Properties](#properties) + 1. [Variables](#variables) + 1. [Hoisting](#hoisting) + 1. [Comparison Operators & Equality](#comparison-operators--equality) + 1. [Blocks](#blocks) + 1. [Comments](#comments) + 1. [Whitespace](#whitespace) + 1. [Commas](#commas) + 1. [Semicolons](#semicolons) + 1. [Type Casting & Coercion](#type-casting--coercion) + 1. [Naming Conventions](#naming-conventions) + 1. [Accessors](#accessors) + 1. [Constructors](#constructors) + 1. [Events](#events) + 1. [Modules](#modules) + 1. [jQuery](#jquery) + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) + 1. [Testing](#testing) + 1. [Performance](#performance) + 1. [Resources](#resources) + 1. [In the Wild](#in-the-wild) + 1. [Translation](#translation) + 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) + 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) + 1. [Contributors](#contributors) + 1. [License](#license) + +## Types + + - **Primitives**: When you access a primitive type you work directly on its value. + + + `string` + + `number` + + `boolean` + + `null` + + `undefined` + + ```javascript + var foo = 1; + var bar = foo; + + bar = 9; + + console.log(foo, bar); // => 1, 9 + ``` + - **Complex**: When you access a complex type you work on a reference to its value. + + + `object` + + `array` + + `function` + + ```javascript + var foo = [1, 2]; + var bar = foo; + + bar[0] = 9; + + console.log(foo[0], bar[0]); // => 9, 9 + ``` + +**[⬆ back to top](#table-of-contents)** + +## Objects + + - Use the literal syntax for object creation. + + ```javascript + // bad + var item = new Object(); + + // good + var item = {}; + ``` + + - Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). + + ```javascript + // bad + var superman = { + default: { clark: 'kent' }, + private: true + }; + + // good + var superman = { + defaults: { clark: 'kent' }, + hidden: true + }; + ``` + + - Use readable synonyms in place of reserved words. + + ```javascript + // bad + var superman = { + class: 'alien' + }; + + // bad + var superman = { + klass: 'alien' + }; + + // good + var superman = { + type: 'alien' + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrays + + - Use the literal syntax for array creation. + + ```javascript + // bad + var items = new Array(); + + // good + var items = []; + ``` + + - Use Array#push instead of direct assignment to add items to an array. + + ```javascript + var someStack = []; + + + // bad + someStack[someStack.length] = 'abracadabra'; + + // good + someStack.push('abracadabra'); + ``` + + - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) + + ```javascript + var len = items.length; + var itemsCopy = []; + var i; + + // bad + for (i = 0; i < len; i++) { + itemsCopy[i] = items[i]; + } + + // good + itemsCopy = items.slice(); + ``` + + - To convert an array-like object to an array, use Array#slice. + + ```javascript + function trigger() { + var args = Array.prototype.slice.call(arguments); + ... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Strings + + - Use single quotes `''` for strings. + + ```javascript + // bad + var name = "Bob Parr"; + + // good + var name = 'Bob Parr'; + + // bad + var fullName = "Bob " + this.lastName; + + // good + var fullName = 'Bob ' + this.lastName; + ``` + + - Strings longer than 100 characters should be written across multiple lines using string concatenation. + - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40). + + ```javascript + // bad + var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; + + // bad + var errorMessage = 'This is a super long error that was thrown because \ + of Batman. When you stop to think about how Batman had anything to do \ + with this, you would get nowhere \ + fast.'; + + // good + var errorMessage = 'This is a super long error that was thrown because ' + + 'of Batman. When you stop to think about how Batman had anything to do ' + + 'with this, you would get nowhere fast.'; + ``` + + - When programmatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). + + ```javascript + var items; + var messages; + var length; + var i; + + messages = [{ + state: 'success', + message: 'This one worked.' + }, { + state: 'success', + message: 'This one worked as well.' + }, { + state: 'error', + message: 'This one did not work.' + }]; + + length = messages.length; + + // bad + function inbox(messages) { + items = ''; + } + + // good + function inbox(messages) { + items = []; + + for (i = 0; i < length; i++) { + // use direct assignment in this case because we're micro-optimizing. + items[i] = '
  • ' + messages[i].message + '
  • '; + } + + return ''; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Functions + + - Function expressions: + + ```javascript + // anonymous function expression + var anonymous = function() { + return true; + }; + + // named function expression + var named = function named() { + return true; + }; + + // immediately-invoked function expression (IIFE) + (function() { + console.log('Welcome to the Internet. Please follow me.'); + })(); + ``` + + - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. + - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). + + ```javascript + // bad + if (currentUser) { + function test() { + console.log('Nope.'); + } + } + + // good + var test; + if (currentUser) { + test = function test() { + console.log('Yup.'); + }; + } + ``` + + - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. + + ```javascript + // bad + function nope(name, options, arguments) { + // ...stuff... + } + + // good + function yup(name, options, args) { + // ...stuff... + } + ``` + +**[⬆ back to top](#table-of-contents)** + + + +## Properties + + - Use dot notation when accessing properties. + + ```javascript + var luke = { + jedi: true, + age: 28 + }; + + // bad + var isJedi = luke['jedi']; + + // good + var isJedi = luke.jedi; + ``` + + - Use subscript notation `[]` when accessing properties with a variable. + + ```javascript + var luke = { + jedi: true, + age: 28 + }; + + function getProp(prop) { + return luke[prop]; + } + + var isJedi = getProp('jedi'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Variables + + - Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. + + ```javascript + // bad + superPower = new SuperPower(); + + // good + var superPower = new SuperPower(); + ``` + + - Use one `var` declaration per variable. + It's easier to add new variable declarations this way, and you never have + to worry about swapping out a `;` for a `,` or introducing punctuation-only + diffs. + + ```javascript + // bad + var items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + var items = getItems(), + goSportsTeam = true; + dragonball = 'z'; + + // good + var items = getItems(); + var goSportsTeam = true; + var dragonball = 'z'; + ``` + + - Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. + + ```javascript + // bad + var i, len, dragonball, + items = getItems(), + goSportsTeam = true; + + // bad + var i; + var items = getItems(); + var dragonball; + var goSportsTeam = true; + var len; + + // good + var items = getItems(); + var goSportsTeam = true; + var dragonball; + var length; + var i; + ``` + + - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. + + ```javascript + // bad + function() { + test(); + console.log('doing stuff..'); + + //..other stuff.. + + var name = getName(); + + if (name === 'test') { + return false; + } + + return name; + } + + // good + function() { + var name = getName(); + + test(); + console.log('doing stuff..'); + + //..other stuff.. + + if (name === 'test') { + return false; + } + + return name; + } + + // bad - unnecessary function call + function() { + var name = getName(); + + if (!arguments.length) { + return false; + } + + this.setFirstName(name); + + return true; + } + + // good + function() { + var name; + + if (!arguments.length) { + return false; + } + + name = getName(); + this.setFirstName(name); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Hoisting + + - Variable declarations get hoisted to the top of their scope, but their assignment does not. + + ```javascript + // we know this wouldn't work (assuming there + // is no notDefined global variable) + function example() { + console.log(notDefined); // => throws a ReferenceError + } + + // creating a variable declaration after you + // reference the variable will work due to + // variable hoisting. Note: the assignment + // value of `true` is not hoisted. + function example() { + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; + } + + // The interpreter is hoisting the variable + // declaration to the top of the scope, + // which means our example could be rewritten as: + function example() { + var declaredButNotAssigned; + console.log(declaredButNotAssigned); // => undefined + declaredButNotAssigned = true; + } + ``` + + - Anonymous function expressions hoist their variable name, but not the function assignment. + + ```javascript + function example() { + console.log(anonymous); // => undefined + + anonymous(); // => TypeError anonymous is not a function + + var anonymous = function() { + console.log('anonymous function expression'); + }; + } + ``` + + - Named function expressions hoist the variable name, not the function name or the function body. + + ```javascript + function example() { + console.log(named); // => undefined + + named(); // => TypeError named is not a function + + superPower(); // => ReferenceError superPower is not defined + + var named = function superPower() { + console.log('Flying'); + }; + } + + // the same is true when the function name + // is the same as the variable name. + function example() { + console.log(named); // => undefined + + named(); // => TypeError named is not a function + + var named = function named() { + console.log('named'); + } + } + ``` + + - Function declarations hoist their name and the function body. + + ```javascript + function example() { + superPower(); // => Flying + + function superPower() { + console.log('Flying'); + } + } + ``` + + - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/). + +**[⬆ back to top](#table-of-contents)** + + + +## Comparison Operators & Equality + + - Use `===` and `!==` over `==` and `!=`. + - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + + + **Objects** evaluate to **true** + + **Undefined** evaluates to **false** + + **Null** evaluates to **false** + + **Booleans** evaluate to **the value of the boolean** + + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** + + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** + + ```javascript + if ([0]) { + // true + // An array is an object, objects evaluate to true + } + ``` + + - Use shortcuts. + + ```javascript + // bad + if (name !== '') { + // ...stuff... + } + + // good + if (name) { + // ...stuff... + } + + // bad + if (collection.length > 0) { + // ...stuff... + } + + // good + if (collection.length) { + // ...stuff... + } + ``` + + - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. + +**[⬆ back to top](#table-of-contents)** + + +## Blocks + + - Use braces with all multi-line blocks. + + ```javascript + // bad + if (test) + return false; + + // good + if (test) return false; + + // good + if (test) { + return false; + } + + // bad + function() { return false; } + + // good + function() { + return false; + } + ``` + + - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your + `if` block's closing brace. + + ```javascript + // bad + if (test) { + thing1(); + thing2(); + } + else { + thing3(); + } + + // good + if (test) { + thing1(); + thing2(); + } else { + thing3(); + } + ``` + + +**[⬆ back to top](#table-of-contents)** + + +## Comments + + - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {String} tag + // @return {Element} element + function make(tag) { + + // ...stuff... + + return element; + } + + // good + /** + * make() returns a new element + * based on the passed in tag name + * + * @param {String} tag + * @return {Element} element + */ + function make(tag) { + + // ...stuff... + + return element; + } + ``` + + - Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment. + + ```javascript + // bad + var active = true; // is current tab + + // good + // is current tab + var active = true; + + // bad + function getType() { + console.log('fetching type...'); + // set the default type to 'no type' + var type = this._type || 'no type'; + + return type; + } + + // good + function getType() { + console.log('fetching type...'); + + // set the default type to 'no type' + var type = this._type || 'no type'; + + return type; + } + ``` + + - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`. + + - Use `// FIXME:` to annotate problems. + + ```javascript + function Calculator() { + + // FIXME: shouldn't use a global here + total = 0; + + return this; + } + ``` + + - Use `// TODO:` to annotate solutions to problems. + + ```javascript + function Calculator() { + + // TODO: total should be configurable by an options param + this.total = 0; + + return this; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Whitespace + + - Use soft tabs set to 2 spaces. + + ```javascript + // bad + function() { + ∙∙∙∙var name; + } + + // bad + function() { + ∙var name; + } + + // good + function() { + ∙∙var name; + } + ``` + + - Place 1 space before the leading brace. + + ```javascript + // bad + function test(){ + console.log('test'); + } + + // good + function test() { + console.log('test'); + } + + // bad + dog.set('attr',{ + age: '1 year', + breed: 'Bernese Mountain Dog' + }); + + // good + dog.set('attr', { + age: '1 year', + breed: 'Bernese Mountain Dog' + }); + ``` + + - Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. + + ```javascript + // bad + if(isJedi) { + fight (); + } + + // good + if (isJedi) { + fight(); + } + + // bad + function fight () { + console.log ('Swooosh!'); + } + + // good + function fight() { + console.log('Swooosh!'); + } + ``` + + - Set off operators with spaces. + + ```javascript + // bad + var x=y+5; + + // good + var x = y + 5; + ``` + + - End files with a single newline character. + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this); + ``` + + ```javascript + // bad + (function(global) { + // ...stuff... + })(this);↵ + ↵ + ``` + + ```javascript + // good + (function(global) { + // ...stuff... + })(this);↵ + ``` + + - Use indentation when making long method chains. Use a leading dot, which + emphasizes that the line is a method call, not a new statement. + + ```javascript + // bad + $('#items').find('.selected').highlight().end().find('.open').updateCount(); + + // bad + $('#items'). + find('.selected'). + highlight(). + end(). + find('.open'). + updateCount(); + + // good + $('#items') + .find('.selected') + .highlight() + .end() + .find('.open') + .updateCount(); + + // bad + var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) + .attr('width', (radius + margin) * 2).append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); + + // good + var leds = stage.selectAll('.led') + .data(data) + .enter().append('svg:svg') + .classed('led', true) + .attr('width', (radius + margin) * 2) + .append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); + ``` + + - Leave a blank line after blocks and before the next statement + + ```javascript + // bad + if (foo) { + return bar; + } + return baz; + + // good + if (foo) { + return bar; + } + + return baz; + + // bad + var obj = { + foo: function() { + }, + bar: function() { + } + }; + return obj; + + // good + var obj = { + foo: function() { + }, + + bar: function() { + } + }; + + return obj; + ``` + + +**[⬆ back to top](#table-of-contents)** + +## Commas + + - Leading commas: **Nope.** + + ```javascript + // bad + var story = [ + once + , upon + , aTime + ]; + + // good + var story = [ + once, + upon, + aTime + ]; + + // bad + var hero = { + firstName: 'Bob' + , lastName: 'Parr' + , heroName: 'Mr. Incredible' + , superPower: 'strength' + }; + + // good + var hero = { + firstName: 'Bob', + lastName: 'Parr', + heroName: 'Mr. Incredible', + superPower: 'strength' + }; + ``` + + - Additional trailing comma: **Nope.** This can cause problems with IE6/7 and IE9 if it's in quirksmode. Also, in some implementations of ES3 would add length to an array if it had an additional trailing comma. This was clarified in ES5 ([source](http://es5.github.io/#D)): + + > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this. + + ```javascript + // bad + var hero = { + firstName: 'Kevin', + lastName: 'Flynn', + }; + + var heroes = [ + 'Batman', + 'Superman', + ]; + + // good + var hero = { + firstName: 'Kevin', + lastName: 'Flynn' + }; + + var heroes = [ + 'Batman', + 'Superman' + ]; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Semicolons + + - **Yup.** + + ```javascript + // bad + (function() { + var name = 'Skywalker' + return name + })() + + // good + (function() { + var name = 'Skywalker'; + return name; + })(); + + // good (guards against the function becoming an argument when two files with IIFEs are concatenated) + ;(function() { + var name = 'Skywalker'; + return name; + })(); + ``` + + [Read more](http://stackoverflow.com/a/7365214/1712802). + +**[⬆ back to top](#table-of-contents)** + + +## Type Casting & Coercion + + - Perform type coercion at the beginning of the statement. + - Strings: + + ```javascript + // => this.reviewScore = 9; + + // bad + var totalScore = this.reviewScore + ''; + + // good + var totalScore = '' + this.reviewScore; + + // bad + var totalScore = '' + this.reviewScore + ' total score'; + + // good + var totalScore = this.reviewScore + ' total score'; + ``` + + - Use `parseInt` for Numbers and always with a radix for type casting. + + ```javascript + var inputValue = '4'; + + // bad + var val = new Number(inputValue); + + // bad + var val = +inputValue; + + // bad + var val = inputValue >> 0; + + // bad + var val = parseInt(inputValue); + + // good + var val = Number(inputValue); + + // good + var val = parseInt(inputValue, 10); + ``` + + - If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. + + ```javascript + // good + /** + * parseInt was the reason my code was slow. + * Bitshifting the String to coerce it to a + * Number made it a lot faster. + */ + var val = inputValue >> 0; + ``` + + - **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: + + ```javascript + 2147483647 >> 0 //=> 2147483647 + 2147483648 >> 0 //=> -2147483648 + 2147483649 >> 0 //=> -2147483647 + ``` + + - Booleans: + + ```javascript + var age = 0; + + // bad + var hasAge = new Boolean(age); + + // good + var hasAge = Boolean(age); + + // good + var hasAge = !!age; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Naming Conventions + + - Avoid single letter names. Be descriptive with your naming. + + ```javascript + // bad + function q() { + // ...stuff... + } + + // good + function query() { + // ..stuff.. + } + ``` + + - Use camelCase when naming objects, functions, and instances. + + ```javascript + // bad + var OBJEcttsssss = {}; + var this_is_my_object = {}; + var o = {}; + function c() {} + + // good + var thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` + + - Use PascalCase when naming constructors or classes. + + ```javascript + // bad + function user(options) { + this.name = options.name; + } + + var bad = new user({ + name: 'nope' + }); + + // good + function User(options) { + this.name = options.name; + } + + var good = new User({ + name: 'yup' + }); + ``` + + - Use a leading underscore `_` when naming private properties. + + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + + // good + this._firstName = 'Panda'; + ``` + + - When saving a reference to `this` use `_this`. + + ```javascript + // bad + function() { + var self = this; + return function() { + console.log(self); + }; + } + + // bad + function() { + var that = this; + return function() { + console.log(that); + }; + } + + // good + function() { + var _this = this; + return function() { + console.log(_this); + }; + } + ``` + + - Name your functions. This is helpful for stack traces. + + ```javascript + // bad + var log = function(msg) { + console.log(msg); + }; + + // good + var log = function log(msg) { + console.log(msg); + }; + ``` + + - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. + + - If your file exports a single class, your filename should be exactly the name of the class. + ```javascript + // file contents + class CheckBox { + // ... + } + module.exports = CheckBox; + + // in some other file + // bad + var CheckBox = require('./checkBox'); + + // bad + var CheckBox = require('./check_box'); + + // good + var CheckBox = require('./CheckBox'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Accessors + + - Accessor functions for properties are not required. + - If you do make accessor functions use getVal() and setVal('hello'). + + ```javascript + // bad + dragon.age(); + + // good + dragon.getAge(); + + // bad + dragon.age(25); + + // good + dragon.setAge(25); + ``` + + - If the property is a boolean, use isVal() or hasVal(). + + ```javascript + // bad + if (!dragon.age()) { + return false; + } + + // good + if (!dragon.hasAge()) { + return false; + } + ``` + + - It's okay to create get() and set() functions, but be consistent. + + ```javascript + function Jedi(options) { + options || (options = {}); + var lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); + } + + Jedi.prototype.set = function(key, val) { + this[key] = val; + }; + + Jedi.prototype.get = function(key) { + return this[key]; + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Constructors + + - Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base! + + ```javascript + function Jedi() { + console.log('new jedi'); + } + + // bad + Jedi.prototype = { + fight: function fight() { + console.log('fighting'); + }, + + block: function block() { + console.log('blocking'); + } + }; + + // good + Jedi.prototype.fight = function fight() { + console.log('fighting'); + }; + + Jedi.prototype.block = function block() { + console.log('blocking'); + }; + ``` + + - Methods can return `this` to help with method chaining. + + ```javascript + // bad + Jedi.prototype.jump = function() { + this.jumping = true; + return true; + }; + + Jedi.prototype.setHeight = function(height) { + this.height = height; + }; + + var luke = new Jedi(); + luke.jump(); // => true + luke.setHeight(20); // => undefined + + // good + Jedi.prototype.jump = function() { + this.jumping = true; + return this; + }; + + Jedi.prototype.setHeight = function(height) { + this.height = height; + return this; + }; + + var luke = new Jedi(); + + luke.jump() + .setHeight(20); + ``` + + + - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + + ```javascript + function Jedi(options) { + options || (options = {}); + this.name = options.name || 'no name'; + } + + Jedi.prototype.getName = function getName() { + return this.name; + }; + + Jedi.prototype.toString = function toString() { + return 'Jedi - ' + this.getName(); + }; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Events + + - When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: + + ```js + // bad + $(this).trigger('listingUpdated', listing.id); + + ... + + $(this).on('listingUpdated', function(e, listingId) { + // do something with listingId + }); + ``` + + prefer: + + ```js + // good + $(this).trigger('listingUpdated', { listingId : listing.id }); + + ... + + $(this).on('listingUpdated', function(e, data) { + // do something with data.listingId + }); + ``` + + **[⬆ back to top](#table-of-contents)** + + +## Modules + + - The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) + - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export. + - Add a method called `noConflict()` that sets the exported module to the previous version and returns this one. + - Always declare `'use strict';` at the top of the module. + + ```javascript + // fancyInput/fancyInput.js + + !function(global) { + 'use strict'; + + var previousFancyInput = global.FancyInput; + + function FancyInput(options) { + this.options = options || {}; + } + + FancyInput.noConflict = function noConflict() { + global.FancyInput = previousFancyInput; + return FancyInput; + }; + + global.FancyInput = FancyInput; + }(this); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## jQuery + + - Prefix jQuery object variables with a `$`. + + ```javascript + // bad + var sidebar = $('.sidebar'); + + // good + var $sidebar = $('.sidebar'); + ``` + + - Cache jQuery lookups. + + ```javascript + // bad + function setSidebar() { + $('.sidebar').hide(); + + // ...stuff... + + $('.sidebar').css({ + 'background-color': 'pink' + }); + } + + // good + function setSidebar() { + var $sidebar = $('.sidebar'); + $sidebar.hide(); + + // ...stuff... + + $sidebar.css({ + 'background-color': 'pink' + }); + } + ``` + + - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + - Use `find` with scoped jQuery object queries. + + ```javascript + // bad + $('ul', '.sidebar').hide(); + + // bad + $('.sidebar').find('ul').hide(); + + // good + $('.sidebar ul').hide(); + + // good + $('.sidebar > ul').hide(); + + // good + $sidebar.find('ul').hide(); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## ECMAScript 5 Compatibility + + - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). + +**[⬆ back to top](#table-of-contents)** + + +## Testing + + - **Yup.** + + ```javascript + function() { + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Performance + + - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) + - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) + - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) + - [Bang Function](http://jsperf.com/bang-function) + - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) + - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) + - [Long String Concatenation](http://jsperf.com/ya-string-concat) + - Loading... + +**[⬆ back to top](#table-of-contents)** + + +## Resources + + +**Read This** + + - [Annotated ECMAScript 5.1](http://es5.github.com/) + +**Tools** + + - Code Style Linters + + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) + + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) + +**Other Style Guides** + + - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) + - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) + - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) + - [JavaScript Standard Style](https://github.com/feross/standard) + +**Other Styles** + + - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen + - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen + - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun + - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman + +**Further Reading** + + - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll + - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer + - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz + - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban + - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock + +**Books** + + - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford + - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov + - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz + - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders + - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas + - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw + - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig + - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch + - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault + - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg + - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy + - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon + - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov + - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman + - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke + - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson + +**Blogs** + + - [DailyJS](http://dailyjs.com/) + - [JavaScript Weekly](http://javascriptweekly.com/) + - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) + - [Bocoup Weblog](http://weblog.bocoup.com/) + - [Adequately Good](http://www.adequatelygood.com/) + - [NCZOnline](http://www.nczonline.net/) + - [Perfection Kills](http://perfectionkills.com/) + - [Ben Alman](http://benalman.com/) + - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) + - [Dustin Diaz](http://dustindiaz.com/) + - [nettuts](http://net.tutsplus.com/?s=javascript) + +**Podcasts** + + - [JavaScript Jabber](http://devchat.tv/js-jabber/) + + +**[⬆ back to top](#table-of-contents)** + +## In the Wild + + This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. + + - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) + - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) + - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) + - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) + - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) + - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) + - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) + - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) + - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) + - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) + - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) + - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) + - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) + - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) + - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) + - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) + - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) + - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) + - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) + - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) + - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) + - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) + - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) + - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) + - **Muber**: [muber/javascript](https://github.com/muber/javascript) + - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) + - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) + - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) + - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) + - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) + - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) + - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) + - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) + - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) + - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) + - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) + - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) + - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) + - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/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) + - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) + - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) + - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) + - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) + +## Translation + + This style guide is also available in other languages: + + - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) + - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) + - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) + - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) + - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) + - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) + - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) + - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) + - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) + - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + +## The JavaScript Style Guide Guide + + - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) + +## Chat With Us About JavaScript + + - Find us on [gitter](https://gitter.im/airbnb/javascript). + +## Contributors + + - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) + + +## License + +(The MIT License) + +Copyright (c) 2014 Airbnb + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**[⬆ back to top](#table-of-contents)** + +# }; diff --git a/es5/README.md b/es5/README.md index 2d24f1a4a2..a70629d728 100644 --- a/es5/README.md +++ b/es5/README.md @@ -1,6 +1,4 @@ -[![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() { +# ~~Airbnb~~ ascribe JavaScript Style Guide() { *A mostly reasonable approach to JavaScript* @@ -39,1704 +37,4 @@ 1. [Contributors](#contributors) 1. [License](#license) -## Types - - - **Primitives**: When you access a primitive type you work directly on its value. - - + `string` - + `number` - + `boolean` - + `null` - + `undefined` - - ```javascript - var foo = 1; - var bar = foo; - - bar = 9; - - console.log(foo, bar); // => 1, 9 - ``` - - **Complex**: When you access a complex type you work on a reference to its value. - - + `object` - + `array` - + `function` - - ```javascript - var foo = [1, 2]; - var bar = foo; - - bar[0] = 9; - - console.log(foo[0], bar[0]); // => 9, 9 - ``` - -**[⬆ back to top](#table-of-contents)** - -## Objects - - - Use the literal syntax for object creation. - - ```javascript - // bad - var item = new Object(); - - // good - var item = {}; - ``` - - - Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61). - - ```javascript - // bad - var superman = { - default: { clark: 'kent' }, - private: true - }; - - // good - var superman = { - defaults: { clark: 'kent' }, - hidden: true - }; - ``` - - - Use readable synonyms in place of reserved words. - - ```javascript - // bad - var superman = { - class: 'alien' - }; - - // bad - var superman = { - klass: 'alien' - }; - - // good - var superman = { - type: 'alien' - }; - ``` - -**[⬆ back to top](#table-of-contents)** - -## Arrays - - - Use the literal syntax for array creation. - - ```javascript - // bad - var items = new Array(); - - // good - var items = []; - ``` - - - Use Array#push instead of direct assignment to add items to an array. - - ```javascript - var someStack = []; - - - // bad - someStack[someStack.length] = 'abracadabra'; - - // good - someStack.push('abracadabra'); - ``` - - - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) - - ```javascript - var len = items.length; - var itemsCopy = []; - var i; - - // bad - for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; - } - - // good - itemsCopy = items.slice(); - ``` - - - To convert an array-like object to an array, use Array#slice. - - ```javascript - function trigger() { - var args = Array.prototype.slice.call(arguments); - ... - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Strings - - - Use single quotes `''` for strings. - - ```javascript - // bad - var name = "Bob Parr"; - - // good - var name = 'Bob Parr'; - - // bad - var fullName = "Bob " + this.lastName; - - // good - var fullName = 'Bob ' + this.lastName; - ``` - - - Strings longer than 100 characters should be written across multiple lines using string concatenation. - - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40). - - ```javascript - // bad - var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.'; - - // bad - var errorMessage = 'This is a super long error that was thrown because \ - of Batman. When you stop to think about how Batman had anything to do \ - with this, you would get nowhere \ - fast.'; - - // good - var errorMessage = 'This is a super long error that was thrown because ' + - 'of Batman. When you stop to think about how Batman had anything to do ' + - 'with this, you would get nowhere fast.'; - ``` - - - When programmatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). - - ```javascript - var items; - var messages; - var length; - var i; - - messages = [{ - state: 'success', - message: 'This one worked.' - }, { - state: 'success', - message: 'This one worked as well.' - }, { - state: 'error', - message: 'This one did not work.' - }]; - - length = messages.length; - - // bad - function inbox(messages) { - items = ''; - } - - // good - function inbox(messages) { - items = []; - - for (i = 0; i < length; i++) { - // use direct assignment in this case because we're micro-optimizing. - items[i] = '
  • ' + messages[i].message + '
  • '; - } - - return ''; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Functions - - - Function expressions: - - ```javascript - // anonymous function expression - var anonymous = function() { - return true; - }; - - // named function expression - var named = function named() { - return true; - }; - - // immediately-invoked function expression (IIFE) - (function() { - console.log('Welcome to the Internet. Please follow me.'); - })(); - ``` - - - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. - - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). - - ```javascript - // bad - if (currentUser) { - function test() { - console.log('Nope.'); - } - } - - // good - var test; - if (currentUser) { - test = function test() { - console.log('Yup.'); - }; - } - ``` - - - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. - - ```javascript - // bad - function nope(name, options, arguments) { - // ...stuff... - } - - // good - function yup(name, options, args) { - // ...stuff... - } - ``` - -**[⬆ back to top](#table-of-contents)** - - - -## Properties - - - Use dot notation when accessing properties. - - ```javascript - var luke = { - jedi: true, - age: 28 - }; - - // bad - var isJedi = luke['jedi']; - - // good - var isJedi = luke.jedi; - ``` - - - Use subscript notation `[]` when accessing properties with a variable. - - ```javascript - var luke = { - jedi: true, - age: 28 - }; - - function getProp(prop) { - return luke[prop]; - } - - var isJedi = getProp('jedi'); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Variables - - - Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. - - ```javascript - // bad - superPower = new SuperPower(); - - // good - var superPower = new SuperPower(); - ``` - - - Use one `var` declaration per variable. - It's easier to add new variable declarations this way, and you never have - to worry about swapping out a `;` for a `,` or introducing punctuation-only - diffs. - - ```javascript - // bad - var items = getItems(), - goSportsTeam = true, - dragonball = 'z'; - - // bad - // (compare to above, and try to spot the mistake) - var items = getItems(), - goSportsTeam = true; - dragonball = 'z'; - - // good - var items = getItems(); - var goSportsTeam = true; - var dragonball = 'z'; - ``` - - - Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. - - ```javascript - // bad - var i, len, dragonball, - items = getItems(), - goSportsTeam = true; - - // bad - var i; - var items = getItems(); - var dragonball; - var goSportsTeam = true; - var len; - - // good - var items = getItems(); - var goSportsTeam = true; - var dragonball; - var length; - var i; - ``` - - - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. - - ```javascript - // bad - function() { - test(); - console.log('doing stuff..'); - - //..other stuff.. - - var name = getName(); - - if (name === 'test') { - return false; - } - - return name; - } - - // good - function() { - var name = getName(); - - test(); - console.log('doing stuff..'); - - //..other stuff.. - - if (name === 'test') { - return false; - } - - return name; - } - - // bad - unnecessary function call - function() { - var name = getName(); - - if (!arguments.length) { - return false; - } - - this.setFirstName(name); - - return true; - } - - // good - function() { - var name; - - if (!arguments.length) { - return false; - } - - name = getName(); - this.setFirstName(name); - - return true; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Hoisting - - - Variable declarations get hoisted to the top of their scope, but their assignment does not. - - ```javascript - // we know this wouldn't work (assuming there - // is no notDefined global variable) - function example() { - console.log(notDefined); // => throws a ReferenceError - } - - // creating a variable declaration after you - // reference the variable will work due to - // variable hoisting. Note: the assignment - // value of `true` is not hoisted. - function example() { - console.log(declaredButNotAssigned); // => undefined - var declaredButNotAssigned = true; - } - - // The interpreter is hoisting the variable - // declaration to the top of the scope, - // which means our example could be rewritten as: - function example() { - var declaredButNotAssigned; - console.log(declaredButNotAssigned); // => undefined - declaredButNotAssigned = true; - } - ``` - - - Anonymous function expressions hoist their variable name, but not the function assignment. - - ```javascript - function example() { - console.log(anonymous); // => undefined - - anonymous(); // => TypeError anonymous is not a function - - var anonymous = function() { - console.log('anonymous function expression'); - }; - } - ``` - - - Named function expressions hoist the variable name, not the function name or the function body. - - ```javascript - function example() { - console.log(named); // => undefined - - named(); // => TypeError named is not a function - - superPower(); // => ReferenceError superPower is not defined - - var named = function superPower() { - console.log('Flying'); - }; - } - - // the same is true when the function name - // is the same as the variable name. - function example() { - console.log(named); // => undefined - - named(); // => TypeError named is not a function - - var named = function named() { - console.log('named'); - } - } - ``` - - - Function declarations hoist their name and the function body. - - ```javascript - function example() { - superPower(); // => Flying - - function superPower() { - console.log('Flying'); - } - } - ``` - - - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/). - -**[⬆ back to top](#table-of-contents)** - - - -## Comparison Operators & Equality - - - Use `===` and `!==` over `==` and `!=`. - - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: - - + **Objects** evaluate to **true** - + **Undefined** evaluates to **false** - + **Null** evaluates to **false** - + **Booleans** evaluate to **the value of the boolean** - + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** - + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** - - ```javascript - if ([0]) { - // true - // An array is an object, objects evaluate to true - } - ``` - - - Use shortcuts. - - ```javascript - // bad - if (name !== '') { - // ...stuff... - } - - // good - if (name) { - // ...stuff... - } - - // bad - if (collection.length > 0) { - // ...stuff... - } - - // good - if (collection.length) { - // ...stuff... - } - ``` - - - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. - -**[⬆ back to top](#table-of-contents)** - - -## Blocks - - - Use braces with all multi-line blocks. - - ```javascript - // bad - if (test) - return false; - - // good - if (test) return false; - - // good - if (test) { - return false; - } - - // bad - function() { return false; } - - // good - function() { - return false; - } - ``` - - - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your - `if` block's closing brace. - - ```javascript - // bad - if (test) { - thing1(); - thing2(); - } - else { - thing3(); - } - - // good - if (test) { - thing1(); - thing2(); - } else { - thing3(); - } - ``` - - -**[⬆ back to top](#table-of-contents)** - - -## Comments - - - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. - - ```javascript - // bad - // make() returns a new element - // based on the passed in tag name - // - // @param {String} tag - // @return {Element} element - function make(tag) { - - // ...stuff... - - return element; - } - - // good - /** - * make() returns a new element - * based on the passed in tag name - * - * @param {String} tag - * @return {Element} element - */ - function make(tag) { - - // ...stuff... - - return element; - } - ``` - - - Use `//` for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment. - - ```javascript - // bad - var active = true; // is current tab - - // good - // is current tab - var active = true; - - // bad - function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - var type = this._type || 'no type'; - - return type; - } - - // good - function getType() { - console.log('fetching type...'); - - // set the default type to 'no type' - var type = this._type || 'no type'; - - return type; - } - ``` - - - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`. - - - Use `// FIXME:` to annotate problems. - - ```javascript - function Calculator() { - - // FIXME: shouldn't use a global here - total = 0; - - return this; - } - ``` - - - Use `// TODO:` to annotate solutions to problems. - - ```javascript - function Calculator() { - - // TODO: total should be configurable by an options param - this.total = 0; - - return this; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Whitespace - - - Use soft tabs set to 2 spaces. - - ```javascript - // bad - function() { - ∙∙∙∙var name; - } - - // bad - function() { - ∙var name; - } - - // good - function() { - ∙∙var name; - } - ``` - - - Place 1 space before the leading brace. - - ```javascript - // bad - function test(){ - console.log('test'); - } - - // good - function test() { - console.log('test'); - } - - // bad - dog.set('attr',{ - age: '1 year', - breed: 'Bernese Mountain Dog' - }); - - // good - dog.set('attr', { - age: '1 year', - breed: 'Bernese Mountain Dog' - }); - ``` - - - Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations. - - ```javascript - // bad - if(isJedi) { - fight (); - } - - // good - if (isJedi) { - fight(); - } - - // bad - function fight () { - console.log ('Swooosh!'); - } - - // good - function fight() { - console.log('Swooosh!'); - } - ``` - - - Set off operators with spaces. - - ```javascript - // bad - var x=y+5; - - // good - var x = y + 5; - ``` - - - End files with a single newline character. - - ```javascript - // bad - (function(global) { - // ...stuff... - })(this); - ``` - - ```javascript - // bad - (function(global) { - // ...stuff... - })(this);↵ - ↵ - ``` - - ```javascript - // good - (function(global) { - // ...stuff... - })(this);↵ - ``` - - - Use indentation when making long method chains. Use a leading dot, which - emphasizes that the line is a method call, not a new statement. - - ```javascript - // bad - $('#items').find('.selected').highlight().end().find('.open').updateCount(); - - // bad - $('#items'). - find('.selected'). - highlight(). - end(). - find('.open'). - updateCount(); - - // good - $('#items') - .find('.selected') - .highlight() - .end() - .find('.open') - .updateCount(); - - // bad - var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) - .attr('width', (radius + margin) * 2).append('svg:g') - .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') - .call(tron.led); - - // good - var leds = stage.selectAll('.led') - .data(data) - .enter().append('svg:svg') - .classed('led', true) - .attr('width', (radius + margin) * 2) - .append('svg:g') - .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') - .call(tron.led); - ``` - - - Leave a blank line after blocks and before the next statement - - ```javascript - // bad - if (foo) { - return bar; - } - return baz; - - // good - if (foo) { - return bar; - } - - return baz; - - // bad - var obj = { - foo: function() { - }, - bar: function() { - } - }; - return obj; - - // good - var obj = { - foo: function() { - }, - - bar: function() { - } - }; - - return obj; - ``` - - -**[⬆ back to top](#table-of-contents)** - -## Commas - - - Leading commas: **Nope.** - - ```javascript - // bad - var story = [ - once - , upon - , aTime - ]; - - // good - var story = [ - once, - upon, - aTime - ]; - - // bad - var hero = { - firstName: 'Bob' - , lastName: 'Parr' - , heroName: 'Mr. Incredible' - , superPower: 'strength' - }; - - // good - var hero = { - firstName: 'Bob', - lastName: 'Parr', - heroName: 'Mr. Incredible', - superPower: 'strength' - }; - ``` - - - Additional trailing comma: **Nope.** This can cause problems with IE6/7 and IE9 if it's in quirksmode. Also, in some implementations of ES3 would add length to an array if it had an additional trailing comma. This was clarified in ES5 ([source](http://es5.github.io/#D)): - - > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this. - - ```javascript - // bad - var hero = { - firstName: 'Kevin', - lastName: 'Flynn', - }; - - var heroes = [ - 'Batman', - 'Superman', - ]; - - // good - var hero = { - firstName: 'Kevin', - lastName: 'Flynn' - }; - - var heroes = [ - 'Batman', - 'Superman' - ]; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Semicolons - - - **Yup.** - - ```javascript - // bad - (function() { - var name = 'Skywalker' - return name - })() - - // good - (function() { - var name = 'Skywalker'; - return name; - })(); - - // good (guards against the function becoming an argument when two files with IIFEs are concatenated) - ;(function() { - var name = 'Skywalker'; - return name; - })(); - ``` - - [Read more](http://stackoverflow.com/a/7365214/1712802). - -**[⬆ back to top](#table-of-contents)** - - -## Type Casting & Coercion - - - Perform type coercion at the beginning of the statement. - - Strings: - - ```javascript - // => this.reviewScore = 9; - - // bad - var totalScore = this.reviewScore + ''; - - // good - var totalScore = '' + this.reviewScore; - - // bad - var totalScore = '' + this.reviewScore + ' total score'; - - // good - var totalScore = this.reviewScore + ' total score'; - ``` - - - Use `parseInt` for Numbers and always with a radix for type casting. - - ```javascript - var inputValue = '4'; - - // bad - var val = new Number(inputValue); - - // bad - var val = +inputValue; - - // bad - var val = inputValue >> 0; - - // bad - var val = parseInt(inputValue); - - // good - var val = Number(inputValue); - - // good - var val = parseInt(inputValue, 10); - ``` - - - If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing. - - ```javascript - // good - /** - * parseInt was the reason my code was slow. - * Bitshifting the String to coerce it to a - * Number made it a lot faster. - */ - var val = inputValue >> 0; - ``` - - - **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109). Largest signed 32-bit Int is 2,147,483,647: - - ```javascript - 2147483647 >> 0 //=> 2147483647 - 2147483648 >> 0 //=> -2147483648 - 2147483649 >> 0 //=> -2147483647 - ``` - - - Booleans: - - ```javascript - var age = 0; - - // bad - var hasAge = new Boolean(age); - - // good - var hasAge = Boolean(age); - - // good - var hasAge = !!age; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Naming Conventions - - - Avoid single letter names. Be descriptive with your naming. - - ```javascript - // bad - function q() { - // ...stuff... - } - - // good - function query() { - // ..stuff.. - } - ``` - - - Use camelCase when naming objects, functions, and instances. - - ```javascript - // bad - var OBJEcttsssss = {}; - var this_is_my_object = {}; - var o = {}; - function c() {} - - // good - var thisIsMyObject = {}; - function thisIsMyFunction() {} - ``` - - - Use PascalCase when naming constructors or classes. - - ```javascript - // bad - function user(options) { - this.name = options.name; - } - - var bad = new user({ - name: 'nope' - }); - - // good - function User(options) { - this.name = options.name; - } - - var good = new User({ - name: 'yup' - }); - ``` - - - Use a leading underscore `_` when naming private properties. - - ```javascript - // bad - this.__firstName__ = 'Panda'; - this.firstName_ = 'Panda'; - - // good - this._firstName = 'Panda'; - ``` - - - When saving a reference to `this` use `_this`. - - ```javascript - // bad - function() { - var self = this; - return function() { - console.log(self); - }; - } - - // bad - function() { - var that = this; - return function() { - console.log(that); - }; - } - - // good - function() { - var _this = this; - return function() { - console.log(_this); - }; - } - ``` - - - Name your functions. This is helpful for stack traces. - - ```javascript - // bad - var log = function(msg) { - console.log(msg); - }; - - // good - var log = function log(msg) { - console.log(msg); - }; - ``` - - - **Note:** IE8 and below exhibit some quirks with named function expressions. See [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/) for more info. - - - If your file exports a single class, your filename should be exactly the name of the class. - ```javascript - // file contents - class CheckBox { - // ... - } - module.exports = CheckBox; - - // in some other file - // bad - var CheckBox = require('./checkBox'); - - // bad - var CheckBox = require('./check_box'); - - // good - var CheckBox = require('./CheckBox'); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Accessors - - - Accessor functions for properties are not required. - - If you do make accessor functions use getVal() and setVal('hello'). - - ```javascript - // bad - dragon.age(); - - // good - dragon.getAge(); - - // bad - dragon.age(25); - - // good - dragon.setAge(25); - ``` - - - If the property is a boolean, use isVal() or hasVal(). - - ```javascript - // bad - if (!dragon.age()) { - return false; - } - - // good - if (!dragon.hasAge()) { - return false; - } - ``` - - - It's okay to create get() and set() functions, but be consistent. - - ```javascript - function Jedi(options) { - options || (options = {}); - var lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); - } - - Jedi.prototype.set = function(key, val) { - this[key] = val; - }; - - Jedi.prototype.get = function(key) { - return this[key]; - }; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Constructors - - - Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base! - - ```javascript - function Jedi() { - console.log('new jedi'); - } - - // bad - Jedi.prototype = { - fight: function fight() { - console.log('fighting'); - }, - - block: function block() { - console.log('blocking'); - } - }; - - // good - Jedi.prototype.fight = function fight() { - console.log('fighting'); - }; - - Jedi.prototype.block = function block() { - console.log('blocking'); - }; - ``` - - - Methods can return `this` to help with method chaining. - - ```javascript - // bad - Jedi.prototype.jump = function() { - this.jumping = true; - return true; - }; - - Jedi.prototype.setHeight = function(height) { - this.height = height; - }; - - var luke = new Jedi(); - luke.jump(); // => true - luke.setHeight(20); // => undefined - - // good - Jedi.prototype.jump = function() { - this.jumping = true; - return this; - }; - - Jedi.prototype.setHeight = function(height) { - this.height = height; - return this; - }; - - var luke = new Jedi(); - - luke.jump() - .setHeight(20); - ``` - - - - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. - - ```javascript - function Jedi(options) { - options || (options = {}); - this.name = options.name || 'no name'; - } - - Jedi.prototype.getName = function getName() { - return this.name; - }; - - Jedi.prototype.toString = function toString() { - return 'Jedi - ' + this.getName(); - }; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Events - - - When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of: - - ```js - // bad - $(this).trigger('listingUpdated', listing.id); - - ... - - $(this).on('listingUpdated', function(e, listingId) { - // do something with listingId - }); - ``` - - prefer: - - ```js - // good - $(this).trigger('listingUpdated', { listingId : listing.id }); - - ... - - $(this).on('listingUpdated', function(e, data) { - // do something with data.listingId - }); - ``` - - **[⬆ back to top](#table-of-contents)** - - -## Modules - - - The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933) - - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export. - - Add a method called `noConflict()` that sets the exported module to the previous version and returns this one. - - Always declare `'use strict';` at the top of the module. - - ```javascript - // fancyInput/fancyInput.js - - !function(global) { - 'use strict'; - - var previousFancyInput = global.FancyInput; - - function FancyInput(options) { - this.options = options || {}; - } - - FancyInput.noConflict = function noConflict() { - global.FancyInput = previousFancyInput; - return FancyInput; - }; - - global.FancyInput = FancyInput; - }(this); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## jQuery - - - Prefix jQuery object variables with a `$`. - - ```javascript - // bad - var sidebar = $('.sidebar'); - - // good - var $sidebar = $('.sidebar'); - ``` - - - Cache jQuery lookups. - - ```javascript - // bad - function setSidebar() { - $('.sidebar').hide(); - - // ...stuff... - - $('.sidebar').css({ - 'background-color': 'pink' - }); - } - - // good - function setSidebar() { - var $sidebar = $('.sidebar'); - $sidebar.hide(); - - // ...stuff... - - $sidebar.css({ - 'background-color': 'pink' - }); - } - ``` - - - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - Use `find` with scoped jQuery object queries. - - ```javascript - // bad - $('ul', '.sidebar').hide(); - - // bad - $('.sidebar').find('ul').hide(); - - // good - $('.sidebar ul').hide(); - - // good - $('.sidebar > ul').hide(); - - // good - $sidebar.find('ul').hide(); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## ECMAScript 5 Compatibility - - - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). - -**[⬆ back to top](#table-of-contents)** - - -## Testing - - - **Yup.** - - ```javascript - function() { - return true; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Performance - - - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) - - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) - - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) - - [Bang Function](http://jsperf.com/bang-function) - - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) - - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) - - [Long String Concatenation](http://jsperf.com/ya-string-concat) - - Loading... - -**[⬆ back to top](#table-of-contents)** - - -## Resources - - -**Read This** - - - [Annotated ECMAScript 5.1](http://es5.github.com/) - -**Tools** - - - Code Style Linters - + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) - + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) - -**Other Style Guides** - - - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) - - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) - - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) - - [JavaScript Standard Style](https://github.com/feross/standard) - -**Other Styles** - - - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen - - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen - - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun - - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman - -**Further Reading** - - - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll - - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer - - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz - - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban - - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock - -**Books** - - - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford - - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov - - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz - - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders - - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas - - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw - - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig - - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch - - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault - - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg - - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy - - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon - - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov - - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman - - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke - - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson - -**Blogs** - - - [DailyJS](http://dailyjs.com/) - - [JavaScript Weekly](http://javascriptweekly.com/) - - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) - - [Bocoup Weblog](http://weblog.bocoup.com/) - - [Adequately Good](http://www.adequatelygood.com/) - - [NCZOnline](http://www.nczonline.net/) - - [Perfection Kills](http://perfectionkills.com/) - - [Ben Alman](http://benalman.com/) - - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) - - [Dustin Diaz](http://dustindiaz.com/) - - [nettuts](http://net.tutsplus.com/?s=javascript) - -**Podcasts** - - - [JavaScript Jabber](http://devchat.tv/js-jabber/) - - -**[⬆ back to top](#table-of-contents)** - -## In the Wild - - This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. - - - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) - - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) - - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) - - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) - - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) - - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) - - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) - - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) - - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) - - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) - - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) - - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) - - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) - - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) - - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) - - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) - - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) - - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) - - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) - - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) - - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) - - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) - - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) - - **Muber**: [muber/javascript](https://github.com/muber/javascript) - - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) - - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) - - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) - - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) - - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) - - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) - - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) - - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) - - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) - - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) - - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) - - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) - - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) - - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/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) - - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) - - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) - - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) - - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) - -## Translation - - This style guide is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) - - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) - - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) - - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide) - - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - -## Chat With Us About JavaScript - - - Find us on [gitter](https://gitter.im/airbnb/javascript). - -## Contributors - - - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) - - -## License - -(The MIT License) - -Copyright (c) 2014 Airbnb - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -**[⬆ back to top](#table-of-contents)** - -# }; +# } diff --git a/react/README-backup.md b/react/README-backup.md new file mode 100644 index 0000000000..dd5592f4ed --- /dev/null +++ b/react/README-backup.md @@ -0,0 +1,315 @@ +# Airbnb React/JSX Style Guide + +*A mostly reasonable approach to React and JSX* + +## Table of Contents + + 1. [Basic Rules](#basic-rules) + 1. [Naming](#naming) + 1. [Declaration](#declaration) + 1. [Alignment](#alignment) + 1. [Quotes](#quotes) + 1. [Spacing](#spacing) + 1. [Props](#props) + 1. [Parentheses](#parentheses) + 1. [Tags](#tags) + 1. [Methods](#methods) + 1. [Ordering](#ordering) + +## Basic Rules + + - Only include one React component per file. + - Always use JSX syntax. + - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. + +## Class vs React.createClass + + - Use class extends React.Component unless you have a very good reason to use mixins. + + ```javascript + // bad + const Listing = React.createClass({ + render() { + return
    ; + } + }); + + // good + class Listing extends React.Component { + render() { + return
    ; + } + } + ``` + +## Naming + + - **Extensions**: Use `.jsx` extension for React components. + - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: + ```javascript + // bad + const reservationCard = require('./ReservationCard'); + + // good + const ReservationCard = require('./ReservationCard'); + + // bad + const ReservationItem = ; + + // good + const reservationItem = ; + ``` + + **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: + ```javascript + // bad + const Footer = require('./Footer/Footer.jsx') + + // bad + const Footer = require('./Footer/index.jsx') + + // good + const Footer = require('./Footer') + ``` + + +## Declaration + - Do not use displayName for naming components. Instead, name the component by reference. + + ```javascript + // bad + export default React.createClass({ + displayName: 'ReservationCard', + // stuff goes here + }); + + // good + export default class ReservationCard extends React.Component { + } + ``` + +## Alignment + - Follow these alignment styles for JSX syntax + + ```javascript + // bad + + + // good + + + // if props fit in one line then keep it on the same line + + + // children get indented normally + + + + ``` + +## Quotes + - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. + + > Why? JSX attributes [can't contain escaped quotes](http://eslint.org/docs/rules/jsx-quotes), so double quotes make conjunctions like `"don't"` easier to type. + > Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention. + + ```javascript + // bad + + + // good + + + // bad + + + // good + + ``` + +## Spacing + - Always include a single space in your self-closing tag. + ```javascript + // bad + + + // very bad + + + // bad + + + // good + + ``` + +## Props + - Always use camelCase for prop names. + ```javascript + // bad + + + // good + + ``` + +## Parentheses + - Wrap JSX tags in parentheses when they span more than one line: + ```javascript + /// bad + render() { + return + + ; + } + + // good + render() { + return ( + + + + ); + } + + // good, when single line + render() { + const body =
    hello
    ; + return {body}; + } + ``` + +## Tags + - Always self-close tags that have no children. + ```javascript + // bad + + + // good + + ``` + + - If your component has multi-line properties, close its tag on a new line. + ```javascript + // bad + + + // good + + ``` + +## Methods + - Do not use underscore prefix for internal methods of a React component. + ```javascript + // bad + React.createClass({ + _onClickSubmit() { + // do stuff + } + + // other stuff + }); + + // good + class extends React.Component { + onClickSubmit() { + // do stuff + } + + // other stuff + }); + ``` + +## Ordering + + - Ordering for class extends React.Component: + + 1. constructor + 1. optional static methods + 1. getChildContext + 1. componentWillMount + 1. componentDidMount + 1. componentWillReceiveProps + 1. shouldComponentUpdate + 1. componentWillUpdate + 1. componentDidUpdate + 1. componentWillUnmount + 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() + 1. *getter methods for render* like getSelectReason() or getFooterContent() + 1. *Optional render methods* like renderNavigation() or renderProfilePicture() + 1. render + + - How to define propTypes, defaultProps, contextTypes, etc... + + ```javascript + import React, { Component, PropTypes } from 'react'; + + const propTypes = { + id: PropTypes.number.isRequired, + url: PropTypes.string.isRequired, + text: PropTypes.string, + }; + + const defaultProps = { + text: 'Hello World', + }; + + export default class Link extends Component { + static methodsAreOk() { + return true; + } + + render() { + return {this.props.text} + } + } + + Link.propTypes = propTypes; + Link.defaultProps = defaultProps; + ``` + + - Ordering for React.createClass: + + 1. displayName + 1. propTypes + 1. contextTypes + 1. childContextTypes + 1. mixins + 1. statics + 1. defaultProps + 1. getDefaultProps + 1. getInitialState + 1. getChildContext + 1. componentWillMount + 1. componentDidMount + 1. componentWillReceiveProps + 1. shouldComponentUpdate + 1. componentWillUpdate + 1. componentDidUpdate + 1. componentWillUnmount + 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() + 1. *getter methods for render* like getSelectReason() or getFooterContent() + 1. *Optional render methods* like renderNavigation() or renderProfilePicture() + 1. render + +**[⬆ back to top](#table-of-contents)** diff --git a/react/README.md b/react/README.md index dd5592f4ed..f8cf4b96e5 100644 --- a/react/README.md +++ b/react/README.md @@ -1,315 +1,19 @@ -# Airbnb React/JSX Style Guide +# ~~Airbnb~~ ascribe React/JSX Style Guide *A mostly reasonable approach to React and JSX* ## Table of Contents - 1. [Basic Rules](#basic-rules) - 1. [Naming](#naming) - 1. [Declaration](#declaration) - 1. [Alignment](#alignment) - 1. [Quotes](#quotes) - 1. [Spacing](#spacing) - 1. [Props](#props) - 1. [Parentheses](#parentheses) - 1. [Tags](#tags) - 1. [Methods](#methods) - 1. [Ordering](#ordering) - -## Basic Rules - - - Only include one React component per file. - - Always use JSX syntax. - - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. - -## Class vs React.createClass - - - Use class extends React.Component unless you have a very good reason to use mixins. - - ```javascript - // bad - const Listing = React.createClass({ - render() { - return
    ; - } - }); - - // good - class Listing extends React.Component { - render() { - return
    ; - } - } - ``` - -## Naming - - - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. - - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: - ```javascript - // bad - const reservationCard = require('./ReservationCard'); - - // good - const ReservationCard = require('./ReservationCard'); - - // bad - const ReservationItem = ; - - // good - const reservationItem = ; - ``` - - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: - ```javascript - // bad - const Footer = require('./Footer/Footer.jsx') - - // bad - const Footer = require('./Footer/index.jsx') - - // good - const Footer = require('./Footer') - ``` - - -## Declaration - - Do not use displayName for naming components. Instead, name the component by reference. - - ```javascript - // bad - export default React.createClass({ - displayName: 'ReservationCard', - // stuff goes here - }); - - // good - export default class ReservationCard extends React.Component { - } - ``` - -## Alignment - - Follow these alignment styles for JSX syntax - - ```javascript - // bad - - - // good - - - // if props fit in one line then keep it on the same line - - - // children get indented normally - - - - ``` - -## Quotes - - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. - - > Why? JSX attributes [can't contain escaped quotes](http://eslint.org/docs/rules/jsx-quotes), so double quotes make conjunctions like `"don't"` easier to type. - > Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention. - - ```javascript - // bad - - - // good - - - // bad - - - // good - - ``` - -## Spacing - - Always include a single space in your self-closing tag. - ```javascript - // bad - - - // very bad - - - // bad - - - // good - - ``` - -## Props - - Always use camelCase for prop names. - ```javascript - // bad - - - // good - - ``` - -## Parentheses - - Wrap JSX tags in parentheses when they span more than one line: - ```javascript - /// bad - render() { - return - - ; - } - - // good - render() { - return ( - - - - ); - } - - // good, when single line - render() { - const body =
    hello
    ; - return {body}; - } - ``` - -## Tags - - Always self-close tags that have no children. - ```javascript - // bad - - - // good - - ``` - - - If your component has multi-line properties, close its tag on a new line. - ```javascript - // bad - - - // good - - ``` - -## Methods - - Do not use underscore prefix for internal methods of a React component. - ```javascript - // bad - React.createClass({ - _onClickSubmit() { - // do stuff - } - - // other stuff - }); - - // good - class extends React.Component { - onClickSubmit() { - // do stuff - } - - // other stuff - }); - ``` - -## Ordering - - - Ordering for class extends React.Component: - - 1. constructor - 1. optional static methods - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() - 1. *getter methods for render* like getSelectReason() or getFooterContent() - 1. *Optional render methods* like renderNavigation() or renderProfilePicture() - 1. render - - - How to define propTypes, defaultProps, contextTypes, etc... - - ```javascript - import React, { Component, PropTypes } from 'react'; - - const propTypes = { - id: PropTypes.number.isRequired, - url: PropTypes.string.isRequired, - text: PropTypes.string, - }; - - const defaultProps = { - text: 'Hello World', - }; - - export default class Link extends Component { - static methodsAreOk() { - return true; - } - - render() { - return {this.props.text} - } - } - - Link.propTypes = propTypes; - Link.defaultProps = defaultProps; - ``` - - - Ordering for React.createClass: - - 1. displayName - 1. propTypes - 1. contextTypes - 1. childContextTypes - 1. mixins - 1. statics - 1. defaultProps - 1. getDefaultProps - 1. getInitialState - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() - 1. *getter methods for render* like getSelectReason() or getFooterContent() - 1. *Optional render methods* like renderNavigation() or renderProfilePicture() - 1. render - -**[⬆ back to top](#table-of-contents)** + 1. [Basic Rules](#basic-rules) #TBD + 1. [Naming](#naming) #TBD + 1. [Declaration](#declaration) #TBD + 1. [Alignment](#alignment) #TBD + 1. [Quotes](#quotes) #TBD + 1. [Spacing](#spacing) #TBD + 1. [Props](#props) #TBD + 1. [Parentheses](#parentheses) #TBD + 1. [Tags](#tags) #TBD + 1. [Methods](#methods) #TBD + 1. [Ordering](#ordering) #TBD + +# } From 1ebb651a1ef30470f51fe9d111a2b04b944a0820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 26 Oct 2015 10:27:20 +0100 Subject: [PATCH 003/143] Readd Types, References, Objects and Arrays to ES6-Readme.md --- README.md | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) diff --git a/README.md b/README.md index 8a62dc6e54..71b616effc 100644 --- a/README.md +++ b/README.md @@ -55,4 +55,282 @@ Other Style Guides 1. [Contributors](#contributors) #TBD 1. [License](#license) #TBD +## Types + + - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. + + + `string` + + `number` + + `boolean` + + `null` + + `undefined` + + ```javascript + const foo = 1; + let bar = foo; + + bar = 9; + + console.log(foo, bar); // => 1, 9 + ``` + - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. + + + `object` + + `array` + + `function` + + ```javascript + const foo = [1, 2]; + const bar = foo; + + bar[0] = 9; + + console.log(foo[0], bar[0]); // => 9, 9 + ``` + +**[⬆ back to top](#table-of-contents)** + +## References + + - [2.1](#2.1) 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; + ``` + + - [2.2](#2.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; + } + ``` + + - [2.3](#2.3) 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 + + - [3.1](#3.1) Use the literal syntax for object creation. + + ```javascript + // bad + const item = new Object(); + + // good + const item = {}; + ``` + + - [3.2](#3.2) If your code will be executed in browsers in script context, 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). It’s OK to use them in ES6 modules and server-side code. + + ```javascript + // bad + const superman = { + default: { clark: 'kent' }, + private: true, + }; + + // good + const superman = { + defaults: { clark: 'kent' }, + hidden: true, + }; + ``` + + - [3.3](#3.3) Use readable synonyms in place of reserved words. + + ```javascript + // bad + const superman = { + class: 'alien', + }; + + // bad + const superman = { + klass: 'alien', + }; + + // good + const superman = { + type: 'alien', + }; + ``` + + + - [3.4](#3.4) 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, + }; + ``` + + + - [3.5](#3.5) 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; + }, + }; + ``` + + + - [3.6](#3.6) 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, + }; + ``` + + - [3.7](#3.7) 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, + twoJediWalkIntoACantina: 2, + lukeSkywalker, + episodeThree: 3, + mayTheFourth: 4, + anakinSkywalker, + }; + + // good + const obj = { + lukeSkywalker, + anakinSkywalker, + episodeOne: 1, + twoJediWalkIntoACantina: 2, + episodeThree: 3, + mayTheFourth: 4, + }; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrays + + - [4.1](#4.1) Use the literal syntax for array creation. + + ```javascript + // bad + const items = new Array(); + + // good + const items = []; + ``` + + - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. + + ```javascript + const someStack = []; + + // bad + someStack[someStack.length] = 'abracadabra'; + + // good + someStack.push('abracadabra'); + ``` + + + - [4.3](#4.3) Use array spreads `...` to copy arrays. + + ```javascript + // bad + const len = items.length; + const itemsCopy = []; + let i; + + for (i = 0; i < len; i++) { + itemsCopy[i] = items[i]; + } + + // good + const itemsCopy = [...items]; + ``` + - [4.4](#4.4) To convert an array-like object to an array, use Array#from. + + ```javascript + const foo = document.querySelectorAll('.foo'); + const nodes = Array.from(foo); + ``` + +**[⬆ back to top](#table-of-contents)** + # } From f1941e3cae47a0dee834ac4da0ce6012c9596b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 26 Oct 2015 10:33:04 +0100 Subject: [PATCH 004/143] Correct table of contents --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 71b616effc..275d194a18 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ Other Style Guides ## Table of Contents - 1. [Types](#types) #TBD - 1. [References](#references) #TBD - 1. [Objects](#objects) #TBD - 1. [Arrays](#arrays) #TBD + 1. [Types](#types) + 1. [References](#references) + 1. [Objects](#objects) + 1. [Arrays](#arrays) 1. [Destructuring](#destructuring) #TBD 1. [Strings](#strings) #TBD 1. [Functions](#functions) #TBD From ed22160ad874343fb888d3093301223acea31d0b Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 26 Oct 2015 10:38:35 +0100 Subject: [PATCH 005/143] Update README.md Small typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a62dc6e54..ce8ef5dd14 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Since all of us liked [Airbnb's JavaScript Style Guide](https://github.com/airbn ## Approach As we want everyone in the team to be able to take part in the creation of this style guide, we decided to have it reviewed and transformed to our specific needs. This is why we're going to remove all the contents of this document, to add them bit-by-bit again through a process of pull-requests and reviews. -Depending on how fast the review will be, every other day there will be a pull a new pull request for everyone to read and comment on. +Depending on how fast the review will be, every other day there will be a new pull request for everyone to read and comment on. As for adjusting the linters, we still need to figure out a way on how to change them efficiently. So if you have suggestions, come forward. From 69a6839ff10c69c31405fb29e624d6d1c1e9f97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 27 Oct 2015 11:14:08 +0100 Subject: [PATCH 006/143] Rename location in example to 'Berlin' --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 275d194a18..f82b083bec 100644 --- a/README.md +++ b/README.md @@ -199,14 +199,14 @@ Other Style Guides // bad const obj = { id: 5, - name: 'San Francisco', + name: 'Berlin', }; obj[getKey('enabled')] = true; // good const obj = { id: 5, - name: 'San Francisco', + name: 'Berlin', [getKey('enabled')]: true, }; ``` From 36acbba803f2b954e1c2e849f97495d9996579f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Wed, 28 Oct 2015 10:25:13 +0100 Subject: [PATCH 007/143] Readd Destructing, Strings, Functions and Arrow Functions to Readme.md --- README.md | 357 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 353 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f7fe36c4ed..15a4bbf0ff 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ Other Style Guides 1. [References](#references) 1. [Objects](#objects) 1. [Arrays](#arrays) - 1. [Destructuring](#destructuring) #TBD - 1. [Strings](#strings) #TBD - 1. [Functions](#functions) #TBD - 1. [Arrow Functions](#arrow-functions) #TBD + 1. [Destructuring](#destructuring) + 1. [Strings](#strings) + 1. [Functions](#functions) + 1. [Arrow Functions](#arrow-functions) 1. [Constructors](#constructors) #TBD 1. [Modules](#modules) #TBD 1. [Iterators and Generators](#iterators-and-generators) #TBD @@ -333,4 +333,353 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** +## Destructuring + + - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. + + > Why? Destructuring saves you from creating temporary references for those properties. + + ```javascript + // 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}`; + } + ``` + + - [5.2](#5.2) Use array destructuring. + + ```javascript + const arr = [1, 2, 3, 4]; + + // bad + const first = arr[0]; + const second = arr[1]; + + // good + const [first, second] = arr; + ``` + + - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. + + > Why? You can add new properties over time or change the order of things without breaking call sites. + + ```javascript + // bad + 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 + + - [6.1](#6.1) Use single quotes `''` for strings. + + ```javascript + // bad + const name = "Capt. Janeway"; + + // good + const name = 'Capt. Janeway'; + ``` + + - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. + - [6.3](#6.3) 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 + 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 + 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 + 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.'; + ``` + + + - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. + + > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. + + ```javascript + // bad + function sayHi(name) { + return 'How are you, ' + name + '?'; + } + + // bad + function sayHi(name) { + return ['How are you, ', name, '?'].join(); + } + + // good + function sayHi(name) { + return `How are you, ${name}?`; + } + ``` + - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. + +**[⬆ back to top](#table-of-contents)** + +## Functions + + - [7.1](#7.1) 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 + // bad + const foo = function () { + }; + + // good + function foo() { + } + ``` + + - [7.2](#7.2) Function expressions: + + ```javascript + // immediately-invoked function expression (IIFE) + (() => { + console.log('Welcome to the Internet. Please follow me.'); + })(); + ``` + + - [7.3](#7.3) 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. + - [7.4](#7.4) **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 + let test; + if (currentUser) { + test = () => { + console.log('Yup.'); + }; + } + ``` + + - [7.5](#7.5) 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... + } + ``` + + + - [7.6](#7.6) 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(''); + } + ``` + + + - [7.7](#7.7) 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 = {}) { + // ... + } + ``` + + - [7.8](#7.8) Avoid side effects with default parameters. + + > Why? They are confusing to reason about. + + ```javascript + var b = 1; + // bad + function count(a = b++) { + console.log(a); + } + count(); // 1 + count(); // 2 + count(3); // 3 + count(); // 3 + ``` + + - [7.9](#7.9) Always put default parameters last. + + ```javascript + // bad + function handleThings(opts = {}, name) { + // ... + } + + // good + function handleThings(name, opts = {}) { + // ... + } + ``` + +- [7.10](#7.10) Never use the Function constructor to create a new function. + + > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. + + ```javascript + // bad + var add = new Function('a', 'b', 'return a + b'); + + // still bad + var subtract = Function('a', 'b', 'return a - b'); + ``` + +**[⬆ back to top](#table-of-contents)** + +## Arrow Functions + + - [8.1](#8.1) 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) { + const y = x + 1; + return x * y; + }); + + // good + [1, 2, 3].map((x) => { + const y = x + 1; + return x * y; + }); + ``` + + - [8.2](#8.2) If the function body consists of a single expression, feel free to omit the braces and use the implicit return. Otherwise 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(number => `A string containing the ${number}.`); + + // bad + [1, 2, 3].map(number => { + const nextNumber = number + 1; + `A string containing the ${nextNumber}.`; + }); + + // good + [1, 2, 3].map(number => { + const nextNumber = number + 1; + return `A string containing the ${nextNumber}.`; + }); + ``` + + - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. + + > Why? It shows clearly where the function starts and ends. + + ```js + // bad + [1, 2, 3].map(number => 'As time went by, the string containing the ' + + `${number} became much longer. So we needed to break it over multiple ` + + 'lines.' + ); + + // good + [1, 2, 3].map(number => ( + `As time went by, the string containing the ${number} became much ` + + 'longer. So we needed to break it over multiple lines.' + )); + ``` + + + - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses. + + > Why? Less visual clutter. + + ```js + // good + [1, 2, 3].map(x => x * x); + + // good + [1, 2, 3].reduce((y, x) => x + y); + ``` + +**[⬆ back to top](#table-of-contents)** + # } From 670f12a3e3faaef65c21d18e030df1b070a4f50f Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Wed, 28 Oct 2015 16:19:56 +0100 Subject: [PATCH 008/143] Add bold font for 'Never' to make them stand out --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 15a4bbf0ff..fcfdc5dd69 100644 --- a/README.md +++ b/README.md @@ -452,7 +452,7 @@ Other Style Guides return `How are you, ${name}?`; } ``` - - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. + - [6.5](#6.5) **NEVER** use eval() on a string, it opens too many vulnerabilities. **[⬆ back to top](#table-of-contents)** @@ -481,7 +481,7 @@ Other Style Guides })(); ``` - - [7.3](#7.3) 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. + - [7.3](#7.3) **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. - [7.4](#7.4) **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 From d108de9c9c4085256637ca8c7ab64af98b424ee4 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Wed, 28 Oct 2015 16:22:43 +0100 Subject: [PATCH 009/143] Missed a few 'Never's that should be bolded --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fcfdc5dd69..62e9712f17 100644 --- a/README.md +++ b/README.md @@ -501,7 +501,7 @@ Other Style Guides } ``` - - [7.5](#7.5) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. + - [7.5](#7.5) **NEVER** name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. ```javascript // bad @@ -516,7 +516,7 @@ Other Style Guides ``` - - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead. + - [7.6](#7.6) **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`. @@ -590,7 +590,7 @@ Other Style Guides } ``` -- [7.10](#7.10) Never use the Function constructor to create a new function. +- [7.10](#7.10) **NEVER** use the Function constructor to create a new function. > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. From 32367eab3a4515d99747ea38102fcb76fa3f1fc9 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Thu, 29 Oct 2015 13:38:58 +0100 Subject: [PATCH 010/143] Move example for 6.3 to 6.2 and add words to 7.2 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 62e9712f17..948430091a 100644 --- a/README.md +++ b/README.md @@ -413,7 +413,6 @@ Other Style Guides ``` - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. - - [6.3](#6.3) 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 @@ -431,6 +430,8 @@ Other Style Guides 'with this, you would get nowhere fast.'; ``` + - [6.3](#6.3) 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). + - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. @@ -472,7 +473,7 @@ Other Style Guides } ``` - - [7.2](#7.2) Function expressions: + - [7.2](#7.2) Immediately-invoked function expressions should use arrow functions as opposed to traditional functions: ```javascript // immediately-invoked function expression (IIFE) From 77054716a8bee8aa73e0d0847fe77d14145b7a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 3 Nov 2015 13:51:04 +0100 Subject: [PATCH 011/143] Add 6.2: Use literals (double and single quotes) according to conveninence --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 15a4bbf0ff..204a7d937b 100644 --- a/README.md +++ b/README.md @@ -412,8 +412,24 @@ Other Style Guides const name = 'Capt. Janeway'; ``` - - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. - - [6.3](#6.3) 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). + - [6.2](#6.2) When using (single- or double) quotes in a string, use the other literal (`''` or `""`). + + ```javascript + // bad + const name = "What a \"nice\" day!"; + + // bad + const name = 'Let\'s go to Rosi\'s!'; + + // good + const name = 'What a "nice" day!'; + + // good + const name = "Let's go to Rosi's!"; + ``` + + - [6.3](#6.3) Strings longer than 100 characters should be written across multiple lines using string concatenation. + - [6.4](#6.4) 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 @@ -432,7 +448,7 @@ Other Style Guides ``` - - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. + - [6.5](#6.5) When programmatically building up strings, use template strings instead of concatenation. > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. @@ -452,7 +468,7 @@ Other Style Guides return `How are you, ${name}?`; } ``` - - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. + - [6.6](#6.6) Never use eval() on a string, it opens too many vulnerabilities. **[⬆ back to top](#table-of-contents)** From 3f94fcd65cd33323f6f2cd66f735c3abc8d4bf40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 3 Nov 2015 16:56:02 +0100 Subject: [PATCH 012/143] Readd Constructors, Modules, Iterators and Generators, Properties and Variables to Readme.md --- README.md | 348 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 343 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1c62a99cdb..6c89822407 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,11 @@ Other Style Guides 1. [Strings](#strings) 1. [Functions](#functions) 1. [Arrow Functions](#arrow-functions) - 1. [Constructors](#constructors) #TBD - 1. [Modules](#modules) #TBD - 1. [Iterators and Generators](#iterators-and-generators) #TBD - 1. [Properties](#properties) #TBD - 1. [Variables](#variables) #TBD + 1. [Constructors](#constructors) + 1. [Modules](#modules) + 1. [Iterators and Generators](#iterators-and-generators) + 1. [Properties](#properties) + 1. [Variables](#variables) 1. [Hoisting](#hoisting) #TBD 1. [Comparison Operators & Equality](#comparison-operators--equality) #TBD 1. [Blocks](#blocks) #TBD @@ -700,4 +700,342 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** +## Constructors + + - [9.1](#9.1) 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; + } + } + ``` + + - [9.2](#9.2) 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]; + } + } + ``` + + - [9.3](#9.3) 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); + ``` + + + - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + + ```javascript + class Jedi { + constructor(options = {}) { + this.name = options.name || 'no name'; + } + + getName() { + return this.name; + } + + toString() { + return `Jedi - ${this.getName()}`; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Modules + + - [10.1](#10.1) 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; + ``` + + - [10.2](#10.2) 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'; + ``` + + - [10.3](#10.3) And do not export directly from an import. + + > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. + + ```javascript + // bad + // filename es6.js + export { es6 as default } from './airbnbStyleGuide'; + + // good + // filename es6.js + import { es6 } from './AirbnbStyleGuide'; + export default es6; + ``` + +**[⬆ back to top](#table-of-contents)** + +## Iterators and Generators + + - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. + + > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. + + ```javascript + const numbers = [1, 2, 3, 4, 5]; + + // bad + let sum = 0; + for (let num of numbers) { + sum += num; + } + + sum === 15; + + // good + let sum = 0; + numbers.forEach((num) => sum += num); + sum === 15; + + // best (use the functional force) + const sum = numbers.reduce((total, num) => total + num, 0); + sum === 15; + ``` + + - [11.2](#11.2) Don't use generators for now. + + > Why? They don't transpile well to ES5. + +**[⬆ back to top](#table-of-contents)** + + +## Properties + + - [12.1](#12.1) Use dot notation when accessing properties. + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + // bad + const isJedi = luke['jedi']; + + // good + const isJedi = luke.jedi; + ``` + + - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. + + ```javascript + const luke = { + jedi: true, + age: 28, + }; + + function getProp(prop) { + return luke[prop]; + } + + const isJedi = getProp('jedi'); + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Variables + + - [13.1](#13.1) 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 + const superPower = new SuperPower(); + ``` + + - [13.2](#13.2) 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 + const items = getItems(), + goSportsTeam = true, + dragonball = 'z'; + + // bad + // (compare to above, and try to spot the mistake) + const items = getItems(), + goSportsTeam = true; + dragonball = 'z'; + + // good + const items = getItems(); + const goSportsTeam = true; + const dragonball = 'z'; + ``` + + - [13.3](#13.3) 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 + let i, len, dragonball, + items = getItems(), + goSportsTeam = true; + + // bad + let i; + const items = getItems(); + let dragonball; + const goSportsTeam = true; + let len; + + // good + const goSportsTeam = true; + const items = getItems(); + let dragonball; + let i; + let length; + ``` + + - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. + + > Why? `let` and `const` are block scoped and not function scoped. + + ```javascript + // good + function() { + test(); + console.log('doing stuff..'); + + //..other stuff.. + + const name = getName(); + + if (name === 'test') { + return false; + } + + return name; + } + + // bad - unnecessary function call + function(hasName) { + const name = getName(); + + if (!hasName) { + return false; + } + + this.setFirstName(name); + + return true; + } + + // good + function(hasName) { + if (!hasName) { + return false; + } + + const name = getName(); + this.setFirstName(name); + + return true; + } + ``` + +**[⬆ back to top](#table-of-contents)** + # } From 397c75bb1ce6e322e6427f3522bdeef533ae9284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Dec 2015 14:06:31 +0100 Subject: [PATCH 013/143] Include feedback given in the pull-request --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6c89822407..a4b08d4b5d 100644 --- a/README.md +++ b/README.md @@ -795,8 +795,8 @@ Other Style Guides ```javascript class Jedi { - constructor(options = {}) { - this.name = options.name || 'no name'; + constructor({ name = 'no name' } = {}) { + this.name = name; } getName() { @@ -863,7 +863,7 @@ Other Style Guides ## Iterators and Generators - - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. + - [11.1](#11.1) Prefer [JavaScript's higher-order functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) like `map()` and `reduce()` instead of loops like `for-of` unless there is a substantial performance disadvantage by doing so. > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. @@ -883,12 +883,14 @@ Other Style Guides numbers.forEach((num) => sum += num); sum === 15; - // best (use the functional force) + // best (use the functional force, Luke) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; ``` - - [11.2](#11.2) Don't use generators for now. + - [11.2](#11.2) Only use `for-in` if you know exactly what you're doing. If unsure, prefer the options given in [11.1](#11.1). + + - [11.3](#11.3) Don't use generators for now. > Why? They don't transpile well to ES5. From 5139323931470efc3378fa00f68140db1f1cabdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Dec 2015 14:13:43 +0100 Subject: [PATCH 014/143] Readd following chapters: - Hoisting - Comparison Operators & Equality - Blocks - Comments - Whitespace --- README.md | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 501 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a4b08d4b5d..53179bcaca 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,11 @@ Other Style Guides 1. [Iterators and Generators](#iterators-and-generators) 1. [Properties](#properties) 1. [Variables](#variables) - 1. [Hoisting](#hoisting) #TBD - 1. [Comparison Operators & Equality](#comparison-operators--equality) #TBD - 1. [Blocks](#blocks) #TBD - 1. [Comments](#comments) #TBD - 1. [Whitespace](#whitespace) #TBD + 1. [Hoisting](#hoisting) + 1. [Comparison Operators & Equality](#comparison-operators--equality) + 1. [Blocks](#blocks) + 1. [Comments](#comments) + 1. [Whitespace](#whitespace) 1. [Commas](#commas) #TBD 1. [Semicolons](#semicolons) #TBD 1. [Type Casting & Coercion](#type-casting--coercion) #TBD @@ -1040,4 +1040,500 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** +## Hoisting + + - [14.1](#14.1) `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 + // 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() { + 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; + } + ``` + + - [14.2](#14.2) 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'); + }; + } + ``` + + - [14.3](#14.3) 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'); + } + } + ``` + + - [14.4](#14.4) 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 + + - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. + - [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract 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 + } + ``` + + - [15.3](#15.3) Use shortcuts. + + ```javascript + // bad + if (name !== '') { + // ...stuff... + } + + // good + if (name) { + // ...stuff... + } + + // bad + if (collection.length > 0) { + // ...stuff... + } + + // good + if (collection.length) { + // ...stuff... + } + ``` + + - [15.4](#15.4) 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 + + - [16.1](#16.1) 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; + } + ``` + + - [16.2](#16.2) 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 + + - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + + ```javascript + // bad + // make() returns a new element + // based on the passed in tag name + // + // @param {String} tag + // @return {Element} element + function make(tag) { + + // ...stuff... + + return element; + } + + // good + /** + * make() returns a new element + * based on the passed in tag name + * + * @param {String} tag + * @return {Element} element + */ + function make(tag) { + + // ...stuff... + + return element; + } + ``` + + - [17.2](#17.2) 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 + const active = true; // is current tab + + // good + // is current tab + const active = true; + + // bad + function getType() { + console.log('fetching type...'); + // set the default type to 'no type' + const type = this._type || 'no type'; + + return type; + } + + // good + function getType() { + console.log('fetching type...'); + + // set the default type to 'no type' + const type = this._type || 'no type'; + + return type; + } + ``` + + - [17.3](#17.3) 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`. + + - [17.4](#17.4) Use `// FIXME:` to annotate problems. + + ```javascript + class Calculator extends Abacus { + constructor() { + super(); + + // FIXME: shouldn't use a global here + total = 0; + } + } + ``` + + - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. + + ```javascript + class Calculator extends Abacus { + constructor() { + super(); + + // TODO: total should be configurable by an options param + this.total = 0; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Whitespace + + - [18.1](#18.1) Use soft tabs set to 2 spaces. + + ```javascript + // bad + function() { + ∙∙∙∙const name; + } + + // bad + function() { + ∙const name; + } + + // good + function() { + ∙∙const name; + } + ``` + + - [18.2](#18.2) 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', + }); + ``` + + - [18.3](#18.3) 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!'); + } + ``` + + - [18.4](#18.4) Set off operators with spaces. + + ```javascript + // bad + const x=y+5; + + // good + const x = y + 5; + ``` + + - [18.5](#18.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);↵ + ``` + + - [18.6](#18.6) 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 + 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 + const 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); + ``` + + - [18.7](#18.7) 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 + const obj = { + foo() { + }, + bar() { + }, + }; + return obj; + + // good + const obj = { + foo() { + }, + + bar() { + }, + }; + + return obj; + + // bad + const arr = [ + function foo() { + }, + function bar() { + }, + ]; + return arr; + + // good + const arr = [ + function foo() { + }, + + function bar() { + }, + ]; + + return arr; + ``` + + +**[⬆ back to top](#table-of-contents)** + # } From dcf6010a7a7002a12d0918110706e03342039b4a Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 12 Jan 2016 10:30:49 +0100 Subject: [PATCH 015/143] Fix whitespace for section --- README.md | 230 +++++++++++++++++++++++++++--------------------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index 53179bcaca..52bf365ad2 100644 --- a/README.md +++ b/README.md @@ -1048,7 +1048,7 @@ Other Style Guides // we know this wouldn't work (assuming there // is no notDefined global variable) function example() { - console.log(notDefined); // => throws a ReferenceError + console.log(notDefined); // => throws a ReferenceError } // creating a variable declaration after you @@ -1056,24 +1056,24 @@ Other Style Guides // variable hoisting. Note: the assignment // value of `true` is not hoisted. function example() { - console.log(declaredButNotAssigned); // => undefined - var declaredButNotAssigned = true; + console.log(declaredButNotAssigned); // => undefined + var declaredButNotAssigned = true; } // The interpreter is hoisting the variable // declaration to the top of the scope, // which means our example could be rewritten as: function example() { - let declaredButNotAssigned; - console.log(declaredButNotAssigned); // => undefined - declaredButNotAssigned = true; + 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; + console.log(declaredButNotAssigned); // => throws a ReferenceError + console.log(typeof declaredButNotAssigned); // => throws a ReferenceError + const declaredButNotAssigned = true; } ``` @@ -1081,13 +1081,13 @@ Other Style Guides ```javascript function example() { - console.log(anonymous); // => undefined + console.log(anonymous); // => undefined - anonymous(); // => TypeError anonymous is not a function + anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { - console.log('anonymous function expression'); - }; + var anonymous = function() { + console.log('anonymous function expression'); + }; } ``` @@ -1095,27 +1095,27 @@ Other Style Guides ```javascript function example() { - console.log(named); // => undefined + console.log(named); // => undefined - named(); // => TypeError named is not a function + named(); // => TypeError named is not a function - superPower(); // => ReferenceError superPower is not defined + superPower(); // => ReferenceError superPower is not defined - var named = function superPower() { - console.log('Flying'); - }; + var named = function superPower() { + console.log('Flying'); + }; } // the same is true when the function name // is the same as the variable name. function example() { - console.log(named); // => undefined + console.log(named); // => undefined - named(); // => TypeError named is not a function + named(); // => TypeError named is not a function - var named = function named() { - console.log('named'); - } + var named = function named() { + console.log('named'); + } } ``` @@ -1123,11 +1123,11 @@ Other Style Guides ```javascript function example() { - superPower(); // => Flying + superPower(); // => Flying - function superPower() { - console.log('Flying'); - } + function superPower() { + console.log('Flying'); + } } ``` @@ -1160,22 +1160,22 @@ Other Style Guides ```javascript // bad if (name !== '') { - // ...stuff... + // ...stuff... } // good if (name) { - // ...stuff... + // ...stuff... } // bad if (collection.length > 0) { - // ...stuff... + // ...stuff... } // good if (collection.length) { - // ...stuff... + // ...stuff... } ``` @@ -1191,14 +1191,14 @@ Other Style Guides ```javascript // bad if (test) - return false; + return false; // good if (test) return false; // good if (test) { - return false; + return false; } // bad @@ -1206,7 +1206,7 @@ Other Style Guides // good function() { - return false; + return false; } ``` @@ -1216,19 +1216,19 @@ Other Style Guides ```javascript // bad if (test) { - thing1(); - thing2(); + thing1(); + thing2(); } else { - thing3(); + thing3(); } // good if (test) { - thing1(); - thing2(); + thing1(); + thing2(); } else { - thing3(); + thing3(); } ``` @@ -1249,9 +1249,9 @@ Other Style Guides // @return {Element} element function make(tag) { - // ...stuff... + // ...stuff... - return element; + return element; } // good @@ -1264,9 +1264,9 @@ Other Style Guides */ function make(tag) { - // ...stuff... + // ...stuff... - return element; + return element; } ``` @@ -1282,21 +1282,21 @@ Other Style Guides // bad function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - const type = this._type || 'no type'; + console.log('fetching type...'); + // set the default type to 'no type' + const type = this._type || 'no type'; - return type; + return type; } // good function getType() { - console.log('fetching type...'); + console.log('fetching type...'); - // set the default type to 'no type' - const type = this._type || 'no type'; + // set the default type to 'no type' + const type = this._type || 'no type'; - return type; + return type; } ``` @@ -1306,12 +1306,12 @@ Other Style Guides ```javascript class Calculator extends Abacus { - constructor() { - super(); + constructor() { + super(); - // FIXME: shouldn't use a global here - total = 0; - } + // FIXME: shouldn't use a global here + total = 0; + } } ``` @@ -1319,12 +1319,12 @@ Other Style Guides ```javascript class Calculator extends Abacus { - constructor() { - super(); + constructor() { + super(); - // TODO: total should be configurable by an options param - this.total = 0; - } + // TODO: total should be configurable by an options param + this.total = 0; + } } ``` @@ -1357,24 +1357,24 @@ Other Style Guides ```javascript // bad function test(){ - console.log('test'); + console.log('test'); } // good function test() { - console.log('test'); + console.log('test'); } // bad dog.set('attr',{ - age: '1 year', - breed: 'Bernese Mountain Dog', + age: '1 year', + breed: 'Bernese Mountain Dog', }); // good dog.set('attr', { - age: '1 year', - breed: 'Bernese Mountain Dog', + age: '1 year', + breed: 'Bernese Mountain Dog', }); ``` @@ -1383,22 +1383,22 @@ Other Style Guides ```javascript // bad if(isJedi) { - fight (); + fight (); } // good if (isJedi) { - fight(); + fight(); } // bad function fight () { - console.log ('Swooosh!'); + console.log ('Swooosh!'); } // good function fight() { - console.log('Swooosh!'); + console.log('Swooosh!'); } ``` @@ -1417,14 +1417,14 @@ Other Style Guides ```javascript // bad (function(global) { - // ...stuff... + // ...stuff... })(this); ``` ```javascript // bad (function(global) { - // ...stuff... + // ...stuff... })(this);↵ ↵ ``` @@ -1432,7 +1432,7 @@ Other Style Guides ```javascript // good (function(global) { - // ...stuff... + // ...stuff... })(this);↵ ``` @@ -1445,35 +1445,35 @@ Other Style Guides // bad $('#items'). - find('.selected'). - highlight(). - end(). - find('.open'). - updateCount(); + find('.selected'). + highlight(). + end(). + find('.open'). + updateCount(); // good $('#items') - .find('.selected') - .highlight() - .end() - .find('.open') - .updateCount(); + .find('.selected') + .highlight() + .end() + .find('.open') + .updateCount(); // bad 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); + .attr('width', (radius + margin) * 2).append('svg:g') + .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') + .call(tron.led); // good const 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); + .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); ``` - [18.7](#18.7) Leave a blank line after blocks and before the next statement. @@ -1481,53 +1481,53 @@ Other Style Guides ```javascript // bad if (foo) { - return bar; + return bar; } return baz; // good if (foo) { - return bar; + return bar; } return baz; // bad const obj = { - foo() { - }, - bar() { - }, + foo() { + }, + bar() { + }, }; return obj; // good const obj = { - foo() { - }, + foo() { + }, - bar() { - }, + bar() { + }, }; return obj; // bad const arr = [ - function foo() { - }, - function bar() { - }, + function foo() { + }, + function bar() { + }, ]; return arr; // good const arr = [ - function foo() { - }, + function foo() { + }, - function bar() { - }, + function bar() { + }, ]; return arr; From af92a7eab0d4302cda06fe1460363890d1690723 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 12 Jan 2016 10:31:23 +0100 Subject: [PATCH 016/143] Add clarifications, etc. --- README.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 52bf365ad2..b91f79e033 100644 --- a/README.md +++ b/README.md @@ -1131,6 +1131,20 @@ Other Style Guides } ``` + - [14.5](#14.5) ES6 `import`s are hoisted to the beginning of their module. + + ```javascript + // This works + foo(); + + import { foo } from 'my_module'; + + // This will import 'imported_module' before 'required_module' + require('required_module'); + + import 'my_module'; + ``` + - 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)** @@ -1138,7 +1152,7 @@ Other Style Guides ## Comparison Operators & Equality - - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. + - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. Avoid `==` and `!=` because they are 'loose' equality comparisons, only evaluating equality after coercing both values following confusing and difficult to remember rules ([see MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness)). - [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: + **Objects** evaluate to **true** @@ -1149,9 +1163,9 @@ Other Style Guides + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** ```javascript - if ([0]) { - // true - // An array is an object, objects evaluate to true + if ([]) { + // true + // An array is an object, objects evaluate to true } ``` From 91342cd03e3fe148817a14a447a7a98ae67816ac Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 12 Jan 2016 10:43:29 +0100 Subject: [PATCH 017/143] Fix tab spacing to be 4 spaces --- README.md | 320 +++++++++++++++++++++++++++--------------------------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index a4b08d4b5d..15f4238a1a 100644 --- a/README.md +++ b/README.md @@ -114,13 +114,13 @@ Other Style Guides // bad var count = 1; if (true) { - count += 1; + count += 1; } // good, use the let. let count = 1; if (true) { - count += 1; + count += 1; } ``` @@ -129,8 +129,8 @@ Other Style Guides ```javascript // const and let only exist in the blocks they are defined in. { - let a = 1; - const b = 1; + let a = 1; + const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError @@ -155,14 +155,14 @@ Other Style Guides ```javascript // bad const superman = { - default: { clark: 'kent' }, - private: true, + default: { clark: 'kent' }, + private: true, }; // good const superman = { - defaults: { clark: 'kent' }, - hidden: true, + defaults: { clark: 'kent' }, + hidden: true, }; ``` @@ -171,17 +171,17 @@ Other Style Guides ```javascript // bad const superman = { - class: 'alien', + class: 'alien', }; // bad const superman = { - klass: 'alien', + klass: 'alien', }; // good const superman = { - type: 'alien', + type: 'alien', }; ``` @@ -193,21 +193,21 @@ Other Style Guides ```javascript function getKey(k) { - return `a key named ${k}`; + return `a key named ${k}`; } // bad const obj = { - id: 5, - name: 'Berlin', + id: 5, + name: 'Berlin', }; obj[getKey('enabled')] = true; // good const obj = { - id: 5, - name: 'Berlin', - [getKey('enabled')]: true, + id: 5, + name: 'Berlin', + [getKey('enabled')]: true, }; ``` @@ -217,20 +217,20 @@ Other Style Guides ```javascript // bad const atom = { - value: 1, + value: 1, - addValue: function (value) { - return atom.value + value; - }, + addValue: function (value) { + return atom.value + value; + }, }; // good const atom = { - value: 1, + value: 1, - addValue(value) { - return atom.value + value; - }, + addValue(value) { + return atom.value + value; + }, }; ``` @@ -244,12 +244,12 @@ Other Style Guides // bad const obj = { - lukeSkywalker: lukeSkywalker, + lukeSkywalker: lukeSkywalker, }; // good const obj = { - lukeSkywalker, + lukeSkywalker, }; ``` @@ -263,22 +263,22 @@ Other Style Guides // bad const obj = { - episodeOne: 1, - twoJediWalkIntoACantina: 2, - lukeSkywalker, - episodeThree: 3, - mayTheFourth: 4, - anakinSkywalker, + episodeOne: 1, + twoJediWalkIntoACantina: 2, + lukeSkywalker, + episodeThree: 3, + mayTheFourth: 4, + anakinSkywalker, }; // good const obj = { - lukeSkywalker, - anakinSkywalker, - episodeOne: 1, - twoJediWalkIntoACantina: 2, - episodeThree: 3, - mayTheFourth: 4, + lukeSkywalker, + anakinSkywalker, + episodeOne: 1, + twoJediWalkIntoACantina: 2, + episodeThree: 3, + mayTheFourth: 4, }; ``` @@ -318,7 +318,7 @@ Other Style Guides let i; for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; + itemsCopy[i] = items[i]; } // good @@ -342,21 +342,21 @@ Other Style Guides ```javascript // bad function getFullName(user) { - const firstName = user.firstName; - const lastName = user.lastName; + const firstName = user.firstName; + const lastName = user.lastName; - return `${firstName} ${lastName}`; + return `${firstName} ${lastName}`; } // good function getFullName(obj) { - const { firstName, lastName } = obj; - return `${firstName} ${lastName}`; + const { firstName, lastName } = obj; + return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { - return `${firstName} ${lastName}`; + return `${firstName} ${lastName}`; } ``` @@ -380,8 +380,8 @@ Other Style Guides ```javascript // bad function processInput(input) { - // then a miracle occurs - return [left, right, top, bottom]; + // then a miracle occurs + return [left, right, top, bottom]; } // the caller needs to think about the order of return data @@ -389,8 +389,8 @@ Other Style Guides // good function processInput(input) { - // then a miracle occurs - return { left, right, top, bottom }; + // then a miracle occurs + return { left, right, top, bottom }; } // the caller selects only the data they need @@ -442,8 +442,8 @@ Other Style Guides // good 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.'; + 'of Batman. When you stop to think about how Batman had anything to do ' + + 'with this, you would get nowhere fast.'; ``` - [6.4](#6.4) 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). @@ -456,17 +456,17 @@ Other Style Guides ```javascript // bad function sayHi(name) { - return 'How are you, ' + name + '?'; + return 'How are you, ' + name + '?'; } // bad function sayHi(name) { - return ['How are you, ', name, '?'].join(); + return ['How are you, ', name, '?'].join(); } // good function sayHi(name) { - return `How are you, ${name}?`; + return `How are you, ${name}?`; } ``` @@ -495,7 +495,7 @@ Other Style Guides ```javascript // immediately-invoked function expression (IIFE) (() => { - console.log('Welcome to the Internet. Please follow me.'); + console.log('Welcome to the Internet. Please follow me.'); })(); ``` @@ -505,17 +505,17 @@ Other Style Guides ```javascript // bad if (currentUser) { - function test() { - console.log('Nope.'); - } + function test() { + console.log('Nope.'); + } } // good let test; if (currentUser) { - test = () => { - console.log('Yup.'); - }; + test = () => { + console.log('Yup.'); + }; } ``` @@ -524,12 +524,12 @@ Other Style Guides ```javascript // bad function nope(name, options, arguments) { - // ...stuff... + // ...stuff... } // good function yup(name, options, args) { - // ...stuff... + // ...stuff... } ``` @@ -541,13 +541,13 @@ Other Style Guides ```javascript // bad function concatenateAll() { - const args = Array.prototype.slice.call(arguments); - return args.join(''); + const args = Array.prototype.slice.call(arguments); + return args.join(''); } // good function concatenateAll(...args) { - return args.join(''); + return args.join(''); } ``` @@ -557,24 +557,24 @@ Other Style Guides ```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 || {}; - // ... + // 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 = {}; - } - // ... + if (opts === void 0) { + opts = {}; + } + // ... } // good function handleThings(opts = {}) { - // ... + // ... } ``` @@ -599,12 +599,12 @@ Other Style Guides ```javascript // bad function handleThings(opts = {}, name) { - // ... + // ... } // good function handleThings(name, opts = {}) { - // ... + // ... } ``` @@ -633,14 +633,14 @@ Other Style Guides ```javascript // bad [1, 2, 3].map(function (x) { - const y = x + 1; - return x * y; + const y = x + 1; + return x * y; }); // good [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; + const y = x + 1; + return x * y; }); ``` @@ -656,14 +656,14 @@ Other Style Guides // bad [1, 2, 3].map(number => { - const nextNumber = number + 1; - `A string containing the ${nextNumber}.`; + const nextNumber = number + 1; + `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map(number => { - const nextNumber = number + 1; - return `A string containing the ${nextNumber}.`; + const nextNumber = number + 1; + return `A string containing the ${nextNumber}.`; }); ``` @@ -674,14 +674,14 @@ Other Style Guides ```js // bad [1, 2, 3].map(number => 'As time went by, the string containing the ' + - `${number} became much longer. So we needed to break it over multiple ` + - 'lines.' + `${number} became much longer. So we needed to break it over multiple ` + + 'lines.' ); // good [1, 2, 3].map(number => ( - `As time went by, the string containing the ${number} became much ` + - 'longer. So we needed to break it over multiple lines.' + `As time went by, the string containing the ${number} became much ` + + 'longer. So we needed to break it over multiple lines.' )); ``` @@ -709,25 +709,25 @@ Other Style Guides ```javascript // bad function Queue(contents = []) { - this._queue = [...contents]; + this._queue = [...contents]; } Queue.prototype.pop = function() { - const value = this._queue[0]; - this._queue.splice(0, 1); - return value; + 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; - } + constructor(contents = []) { + this._queue = [...contents]; + } + pop() { + const value = this._queue[0]; + this._queue.splice(0, 1); + return value; + } } ``` @@ -739,18 +739,18 @@ Other Style Guides // bad const inherits = require('inherits'); function PeekableQueue(contents) { - Queue.apply(this, contents); + Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function() { - return this._queue[0]; + return this._queue[0]; } // good class PeekableQueue extends Queue { - peek() { - return this._queue[0]; - } + peek() { + return this._queue[0]; + } } ``` @@ -759,12 +759,12 @@ Other Style Guides ```javascript // bad Jedi.prototype.jump = function() { - this.jumping = true; - return true; + this.jumping = true; + return true; }; Jedi.prototype.setHeight = function(height) { - this.height = height; + this.height = height; }; const luke = new Jedi(); @@ -773,21 +773,21 @@ Other Style Guides // good class Jedi { - jump() { - this.jumping = true; - return this; - } - - setHeight(height) { - this.height = height; - return this; - } + jump() { + this.jumping = true; + return this; + } + + setHeight(height) { + this.height = height; + return this; + } } const luke = new Jedi(); luke.jump() - .setHeight(20); + .setHeight(20); ``` @@ -795,17 +795,17 @@ Other Style Guides ```javascript class Jedi { - constructor({ name = 'no name' } = {}) { - this.name = name; - } + constructor({ name = 'no name' } = {}) { + this.name = name; + } - getName() { - return this.name; - } + getName() { + return this.name; + } - toString() { - return `Jedi - ${this.getName()}`; - } + toString() { + return `Jedi - ${this.getName()}`; + } } ``` @@ -873,7 +873,7 @@ Other Style Guides // bad let sum = 0; for (let num of numbers) { - sum += num; + sum += num; } sum === 15; @@ -903,8 +903,8 @@ Other Style Guides ```javascript const luke = { - jedi: true, - age: 28, + jedi: true, + age: 28, }; // bad @@ -918,12 +918,12 @@ Other Style Guides ```javascript const luke = { - jedi: true, - age: 28, + jedi: true, + age: 28, }; function getProp(prop) { - return luke[prop]; + return luke[prop]; } const isJedi = getProp('jedi'); @@ -951,14 +951,14 @@ Other Style Guides ```javascript // bad const items = getItems(), - goSportsTeam = true, - dragonball = 'z'; + goSportsTeam = true, + dragonball = 'z'; // bad // (compare to above, and try to spot the mistake) const items = getItems(), - goSportsTeam = true; - dragonball = 'z'; + goSportsTeam = true; + dragonball = 'z'; // good const items = getItems(); @@ -998,43 +998,43 @@ Other Style Guides ```javascript // good function() { - test(); - console.log('doing stuff..'); + test(); + console.log('doing stuff..'); - //..other stuff.. + //..other stuff.. - const name = getName(); + const name = getName(); - if (name === 'test') { - return false; - } + if (name === 'test') { + return false; + } - return name; + return name; } // bad - unnecessary function call function(hasName) { - const name = getName(); + const name = getName(); - if (!hasName) { - return false; - } + if (!hasName) { + return false; + } - this.setFirstName(name); + this.setFirstName(name); - return true; + return true; } // good function(hasName) { - if (!hasName) { - return false; - } + if (!hasName) { + return false; + } - const name = getName(); - this.setFirstName(name); + const name = getName(); + this.setFirstName(name); - return true; + return true; } ``` From 6c09768f088b6aa5e5989fb0b38e175d45cb1841 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 12 Jan 2016 10:43:43 +0100 Subject: [PATCH 018/143] Small changes for variables section --- README.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 15f4238a1a..4f4084dd44 100644 --- a/README.md +++ b/README.md @@ -671,7 +671,7 @@ Other Style Guides > Why? It shows clearly where the function starts and ends. - ```js + ```javascript // bad [1, 2, 3].map(number => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + @@ -690,7 +690,7 @@ Other Style Guides > Why? Less visual clutter. - ```js + ```javascript // good [1, 2, 3].map(x => x * x); @@ -934,7 +934,7 @@ Other Style Guides ## Variables - - [13.1](#13.1) 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. + - [13.1](#13.1) Always use `const` or `let` 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 @@ -944,7 +944,7 @@ Other Style Guides const superPower = new SuperPower(); ``` - - [13.2](#13.2) Use one `const` declaration per variable. + - [13.2](#13.2) Use one `const` or `let` 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. @@ -1038,6 +1038,15 @@ Other Style Guides } ``` + > Note that referencing a variable declared by `let` or `const` before they are set results in a reference error, including typeof (see [Why `typeof` is no longer "safe"](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15)) + + ```javascript + if (condition) { + console.log(typeof value); // ReferenceError! + let value = "blue"; + } + ``` + **[⬆ back to top](#table-of-contents)** # } From abcdbb3b05bd3bd20030e92c3eda07e19c51b3ff Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 12 Jan 2016 10:50:42 +0100 Subject: [PATCH 019/143] Change tab spacing to be 4 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b91f79e033..c8cdc279e9 100644 --- a/README.md +++ b/README.md @@ -1347,10 +1347,10 @@ Other Style Guides ## Whitespace - - [18.1](#18.1) Use soft tabs set to 2 spaces. + - [18.1](#18.1) Use soft tabs set to 4 spaces. ```javascript - // bad + // good function() { ∙∙∙∙const name; } @@ -1360,7 +1360,7 @@ Other Style Guides ∙const name; } - // good + // bad function() { ∙∙const name; } From fd95e0ff423725491d11da3910164dba455f2b4d Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 18 Jan 2016 13:56:08 +0100 Subject: [PATCH 020/143] Add multiline destructuring rule --- README.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a4b08d4b5d..83d442784a 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,25 @@ Other Style Guides } ``` - - [5.2](#5.2) Use array destructuring. + - [5.2](#5.2) When destructuring requires multiple lines, inline the initial property. + + ```javascript + // bad + const { + first, + second + } = obj; + + // good + let { first, + second } = obj; + + // good + const { first, + second } = obj; + ``` + + - [5.3](#5.3) Use array destructuring. ```javascript const arr = [1, 2, 3, 4]; @@ -373,7 +391,7 @@ Other Style Guides const [first, second] = arr; ``` - - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. + - [5.4](#5.4) 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. From 710e6af7df6794cc2b9bc86395217b485105ddd5 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 26 Jan 2016 10:08:28 +0100 Subject: [PATCH 021/143] Add changes based on comments --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c8cdc279e9..667caebeca 100644 --- a/README.md +++ b/README.md @@ -1252,7 +1252,7 @@ Other Style Guides ## Comments - - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. + - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values by using [JSDoc](http://www.2ality.com/2011/08/jsdoc-intro.html). ```javascript // bad @@ -1392,7 +1392,7 @@ Other Style Guides }); ``` - - [18.3](#18.3) 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. + - [18.3](#18.3) Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.) and anonymous function declarations. Place no space before the argument list in function calls and named declarations. ```javascript // bad @@ -1405,6 +1405,16 @@ Other Style Guides fight(); } + // bad + function() { + console.log('Anonymous'); + } + + // good -- easier to tell this is a function decarlation rather than function call + function () { + console.log('Anonymous'); + } + // bad function fight () { console.log ('Swooosh!'); @@ -1474,20 +1484,13 @@ Other Style Guides .updateCount(); // bad - 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); + const request = fetch('/users').then(...).catch(...).finally(...); // good - const 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); + const request = fetch('/users') + .then(...) + .catch(...) + .finally(...); ``` - [18.7](#18.7) Leave a blank line after blocks and before the next statement. @@ -1547,6 +1550,31 @@ Other Style Guides return arr; ``` + - [18.8](#18.8) Break long logical operations into multiple lines, leaving operators at the end of the line and intenting the later lines to the first line's first operand. + + ```javascript + // bad + if (aReallyReallyLongExpr && anotherSuperLongExpr && wowSoManyExpr && longExprToCheckTheWorldIsOk) { + ... + } + + // good + if (aReallyReallyLongExpr && + anotherSuperLongExpr && + wowSoManyExpr && + longExprToCheckTheWorldIsOk) { + ... + } + + // good + while (aReallyReallyLongExpr && + anotherSuperLongExpr && + wowSoManyExpr && + longExprToCheckTheWorldIsOk) { + ... + } + ``` + **[⬆ back to top](#table-of-contents)** From 7173daa4f1e509e59726d7cc510d8a06d42ebca7 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 26 Jan 2016 10:13:17 +0100 Subject: [PATCH 022/143] Fix typo in import hoisting section --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 667caebeca..1e4ce8e97a 100644 --- a/README.md +++ b/README.md @@ -1131,7 +1131,7 @@ Other Style Guides } ``` - - [14.5](#14.5) ES6 `import`s are hoisted to the beginning of their module. + - [14.5](#14.5) ES6 `import`s are hoisted to the beginning of their module while modules imported through `require`s (ie. CommonJS modules) are not. ```javascript // This works @@ -1142,7 +1142,7 @@ Other Style Guides // This will import 'imported_module' before 'required_module' require('required_module'); - import 'my_module'; + import 'imported_module'; ``` - 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/). From 532153ef4655b6a7690e4d843f835e4b8aa6c07a Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 26 Jan 2016 10:29:12 +0100 Subject: [PATCH 023/143] Readd following chapters: - Commas - Semicolons - Type Casting & Coercion - Naming Conventions - Accessors - Events - jQuery --- README.md | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) diff --git a/README.md b/README.md index 88b60ee080..08b2f91b72 100644 --- a/README.md +++ b/README.md @@ -1605,4 +1605,477 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** + +## Commas + + - [19.1](#19.1) Leading commas: **Nope.** + + ```javascript + // bad + const story = [ + once + , upon + , aTime + ]; + + // good + const story = [ + once, + upon, + aTime, + ]; + + // bad + const hero = { + firstName: 'Ada' + , lastName: 'Lovelace' + , birthYear: 1815 + , superPower: 'computers' + }; + + // good + const hero = { + firstName: 'Ada', + lastName: 'Lovelace', + birthYear: 1815, + superPower: 'computers', + }; + ``` + + - [19.2](#19.2) Additional trailing comma: **Yup.** + + > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers. + + ```javascript + // bad - git diff without trailing comma + const hero = { + firstName: 'Florence', + - lastName: 'Nightingale' + + lastName: 'Nightingale', + + inventorOf: ['coxcomb graph', 'modern nursing'] + }; + + // good - git diff with trailing comma + const hero = { + firstName: 'Florence', + lastName: 'Nightingale', + + inventorOf: ['coxcomb chart', 'modern nursing'], + }; + + // bad + const hero = { + firstName: 'Dana', + lastName: 'Scully' + }; + + const heroes = [ + 'Batman', + 'Superman' + ]; + + // good + const hero = { + firstName: 'Dana', + lastName: 'Scully', + }; + + const heroes = [ + 'Batman', + 'Superman', + ]; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Semicolons + + - [20.1](#20.1) **Yup.** + + ```javascript + // bad + (function() { + const name = 'Skywalker' + return name + })() + + // good + (() => { + const name = 'Skywalker'; + return name; + })(); + + // good (guards against the function becoming an argument when two files with IIFEs are concatenated) + ;(() => { + const name = 'Skywalker'; + return name; + })(); + ``` + + [Read more](http://stackoverflow.com/a/7365214/1712802). + +**[⬆ back to top](#table-of-contents)** + + +## Type Casting & Coercion + + - [21.1](#21.1) Perform type coercion at the beginning of the statement. + - [21.2](#21.2) Strings: + + ```javascript + // => this.reviewScore = 9; + + // bad + const totalScore = this.reviewScore + ''; + + // good + const totalScore = String(this.reviewScore); + ``` + + - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. + + ```javascript + const inputValue = '4'; + + // bad + const val = new Number(inputValue); + + // bad + const val = +inputValue; + + // bad + const val = inputValue >> 0; + + // bad + const val = parseInt(inputValue); + + // good + const val = Number(inputValue); + + // good + const val = parseInt(inputValue, 10); + ``` + + - [21.4](#21.4) 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. + */ + const val = inputValue >> 0; + ``` + + - [21.5](#21.5) **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 + ``` + + - [21.6](#21.6) Booleans: + + ```javascript + const age = 0; + + // bad + const hasAge = new Boolean(age); + + // good + const hasAge = Boolean(age); + + // good + const hasAge = !!age; + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Naming Conventions + + - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. + + ```javascript + // bad + function q() { + // ...stuff... + } + + // good + function query() { + // ..stuff.. + } + ``` + + - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. + + ```javascript + // bad + const OBJEcttsssss = {}; + const this_is_my_object = {}; + function c() {} + + // good + const thisIsMyObject = {}; + function thisIsMyFunction() {} + ``` + + - [22.3](#22.3) Use PascalCase when naming constructors or classes. + + ```javascript + // bad + function user(options) { + this.name = options.name; + } + + const bad = new user({ + name: 'nope', + }); + + // good + class User { + constructor(options) { + this.name = options.name; + } + } + + const good = new User({ + name: 'yup', + }); + ``` + + - [22.4](#22.4) Use a leading underscore `_` when naming private properties. + + ```javascript + // bad + this.__firstName__ = 'Panda'; + this.firstName_ = 'Panda'; + + // good + this._firstName = 'Panda'; + ``` + + - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. + + ```javascript + // bad + function foo() { + const self = this; + return function() { + console.log(self); + }; + } + + // bad + function foo() { + const that = this; + return function() { + console.log(that); + }; + } + + // good + function foo() { + return () => { + console.log(this); + }; + } + ``` + + - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. + ```javascript + // file contents + class CheckBox { + // ... + } + export default CheckBox; + + // in some other file + // bad + import CheckBox from './checkBox'; + + // bad + import CheckBox from './check_box'; + + // good + import CheckBox from './CheckBox'; + ``` + + - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. + + ```javascript + function makeStyleGuide() { + } + + export default makeStyleGuide; + ``` + + - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. + + ```javascript + const AirbnbStyleGuide = { + es6: { + } + }; + + export default AirbnbStyleGuide; + ``` + + +**[⬆ back to top](#table-of-contents)** + + +## Accessors + + - [23.1](#23.1) Accessor functions for properties are not required. + - [23.2](#23.2) 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); + ``` + + - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. + + ```javascript + // bad + if (!dragon.age()) { + return false; + } + + // good + if (!dragon.hasAge()) { + return false; + } + ``` + + - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. + + ```javascript + class Jedi { + constructor(options = {}) { + const lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); + } + + set(key, val) { + this[key] = val; + } + + get(key) { + return this[key]; + } + } + ``` + +**[⬆ back to top](#table-of-contents)** + + +## Events + + - [24.1](#24.1) 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: + + ```javascript + // bad + $(this).trigger('listingUpdated', listing.id); + + ... + + $(this).on('listingUpdated', function(e, listingId) { + // do something with listingId + }); + ``` + + prefer: + + ```javascript + // good + $(this).trigger('listingUpdated', { listingId: listing.id }); + + ... + + $(this).on('listingUpdated', function(e, data) { + // do something with data.listingId + }); + ``` + + **[⬆ back to top](#table-of-contents)** + + +## jQuery + + - [25.1](#25.1) Prefix jQuery object variables with a `$`. + + ```javascript + // bad + const sidebar = $('.sidebar'); + + // good + const $sidebar = $('.sidebar'); + + // good + const $sidebarBtn = $('.sidebar-btn'); + ``` + + - [25.2](#25.2) Cache jQuery lookups. + + ```javascript + // bad + function setSidebar() { + $('.sidebar').hide(); + + // ...stuff... + + $('.sidebar').css({ + 'background-color': 'pink' + }); + } + + // good + function setSidebar() { + const $sidebar = $('.sidebar'); + $sidebar.hide(); + + // ...stuff... + + $sidebar.css({ + 'background-color': 'pink' + }); + } + ``` + + - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) + - [25.4](#25.4) 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)** + # } From c64841b8648781993fd33d701176d4f35b6834ce Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Tue, 26 Jan 2016 10:35:33 +0100 Subject: [PATCH 024/143] Remove #TBDs of readded sections --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 08b2f91b72..5f0a921aa2 100644 --- a/README.md +++ b/README.md @@ -36,14 +36,14 @@ Other Style Guides 1. [Blocks](#blocks) 1. [Comments](#comments) 1. [Whitespace](#whitespace) - 1. [Commas](#commas) #TBD - 1. [Semicolons](#semicolons) #TBD - 1. [Type Casting & Coercion](#type-casting--coercion) #TBD - 1. [Naming Conventions](#naming-conventions) #TBD - 1. [Accessors](#accessors) #TBD - 1. [Events](#events) #TBD - 1. [jQuery](#jquery) #TBD - 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) #TBD #TBD + 1. [Commas](#commas) + 1. [Semicolons](#semicolons) + 1. [Type Casting & Coercion](#type-casting--coercion) + 1. [Naming Conventions](#naming-conventions) + 1. [Accessors](#accessors) + 1. [Events](#events) + 1. [jQuery](#jquery) + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) #TBD 1. [ECMAScript 6 Styles](#ecmascript-6-styles) #TBD 1. [Testing](#testing) #TBD 1. [Performance](#performance) #TBD From 3c6e8a258b78ac5d9b84a7443f99bf23dbcaa221 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 8 Feb 2016 12:26:57 +0100 Subject: [PATCH 025/143] Fix PR comments and whitespace --- README.md | 183 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 95 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index 5f0a921aa2..e67e4d172d 100644 --- a/README.md +++ b/README.md @@ -1613,32 +1613,32 @@ Other Style Guides ```javascript // bad const story = [ - once - , upon - , aTime + once + , upon + , aTime ]; // good const story = [ - once, - upon, - aTime, + once, + upon, + aTime, ]; // bad const hero = { - firstName: 'Ada' - , lastName: 'Lovelace' - , birthYear: 1815 - , superPower: 'computers' + firstName: 'Ada' + , lastName: 'Lovelace' + , birthYear: 1815 + , superPower: 'computers' }; // good const hero = { - firstName: 'Ada', - lastName: 'Lovelace', - birthYear: 1815, - superPower: 'computers', + firstName: 'Ada', + lastName: 'Lovelace', + birthYear: 1815, + superPower: 'computers', }; ``` @@ -1649,39 +1649,39 @@ Other Style Guides ```javascript // bad - git diff without trailing comma const hero = { - firstName: 'Florence', - - lastName: 'Nightingale' - + lastName: 'Nightingale', - + inventorOf: ['coxcomb graph', 'modern nursing'] + firstName: 'Florence', + - lastName: 'Nightingale' + + lastName: 'Nightingale', + + inventorOf: ['coxcomb graph', 'modern nursing'] }; // good - git diff with trailing comma const hero = { - firstName: 'Florence', - lastName: 'Nightingale', - + inventorOf: ['coxcomb chart', 'modern nursing'], + firstName: 'Florence', + lastName: 'Nightingale', + + inventorOf: ['coxcomb chart', 'modern nursing'], }; // bad const hero = { - firstName: 'Dana', - lastName: 'Scully' + firstName: 'Dana', + lastName: 'Scully' }; const heroes = [ - 'Batman', - 'Superman' + 'Batman', + 'Superman' ]; // good const hero = { - firstName: 'Dana', - lastName: 'Scully', + firstName: 'Dana', + lastName: 'Scully', }; const heroes = [ - 'Batman', - 'Superman', + 'Batman', + 'Superman', ]; ``` @@ -1695,20 +1695,20 @@ Other Style Guides ```javascript // bad (function() { - const name = 'Skywalker' - return name + const name = 'Skywalker' + return name })() // good (() => { - const name = 'Skywalker'; - return name; + const name = 'Skywalker'; + return name; })(); // good (guards against the function becoming an argument when two files with IIFEs are concatenated) ;(() => { - const name = 'Skywalker'; - return name; + const name = 'Skywalker'; + return name; })(); ``` @@ -1732,7 +1732,7 @@ Other Style Guides const totalScore = String(this.reviewScore); ``` - - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. + - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix. ```javascript const inputValue = '4'; @@ -1801,12 +1801,12 @@ Other Style Guides ```javascript // bad function q() { - // ...stuff... + // ...stuff... } // good function query() { - // ..stuff.. + // ..stuff.. } ``` @@ -1828,22 +1828,22 @@ Other Style Guides ```javascript // bad function user(options) { - this.name = options.name; + this.name = options.name; } const bad = new user({ - name: 'nope', + name: 'nope', }); // good - class User { - constructor(options) { - this.name = options.name; - } + class UserPascalCase { + constructor(options) { + this.name = options.name; + } } - const good = new User({ - name: 'yup', + const good = new UserPascalCase({ + name: 'yup', }); ``` @@ -1863,33 +1863,40 @@ Other Style Guides ```javascript // bad function foo() { - const self = this; - return function() { - console.log(self); - }; + const self = this; + return function() { + console.log(self); + }; } // bad function foo() { - const that = this; - return function() { - console.log(that); - }; + const that = this; + return function() { + console.log(that); + }; + } + + // good + function foo() { + return () => { + console.log(this); + }; } // good function foo() { - return () => { - console.log(this); - }; + return (function() { + console.log(this); + }).bind(this); } ``` - - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. + - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class, converted from PascalCase to snake_case. ```javascript // file contents class CheckBox { - // ... + // ... } export default CheckBox; @@ -1898,10 +1905,10 @@ Other Style Guides import CheckBox from './checkBox'; // bad - import CheckBox from './check_box'; + import CheckBox from './CheckBox'; // good - import CheckBox from './CheckBox'; + import CheckBox from './check_box'; ``` - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. @@ -1917,8 +1924,8 @@ Other Style Guides ```javascript const AirbnbStyleGuide = { - es6: { - } + es6: { + } }; export default AirbnbStyleGuide; @@ -1952,12 +1959,12 @@ Other Style Guides ```javascript // bad if (!dragon.age()) { - return false; + return false; } // good if (!dragon.hasAge()) { - return false; + return false; } ``` @@ -1965,18 +1972,18 @@ Other Style Guides ```javascript class Jedi { - constructor(options = {}) { - const lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); - } + constructor(options = {}) { + const lightsaber = options.lightsaber || 'blue'; + this.set('lightsaber', lightsaber); + } - set(key, val) { - this[key] = val; - } + set(key, val) { + this[key] = val; + } - get(key) { - return this[key]; - } + get(key) { + return this[key]; + } } ``` @@ -1994,7 +2001,7 @@ Other Style Guides ... $(this).on('listingUpdated', function(e, listingId) { - // do something with listingId + // do something with listingId }); ``` @@ -2007,7 +2014,7 @@ Other Style Guides ... $(this).on('listingUpdated', function(e, data) { - // do something with data.listingId + // do something with data.listingId }); ``` @@ -2034,25 +2041,25 @@ Other Style Guides ```javascript // bad function setSidebar() { - $('.sidebar').hide(); + $('.sidebar').hide(); - // ...stuff... + // ...stuff... - $('.sidebar').css({ - 'background-color': 'pink' - }); + $('.sidebar').css({ + 'background-color': 'pink' + }); } // good function setSidebar() { - const $sidebar = $('.sidebar'); - $sidebar.hide(); + const $sidebar = $('.sidebar'); + $sidebar.hide(); - // ...stuff... + // ...stuff... - $sidebar.css({ - 'background-color': 'pink' - }); + $sidebar.css({ + 'background-color': 'pink' + }); } ``` From eea3eb3e5dae8c70c04e615450866fd08813b28f Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 8 Feb 2016 12:37:11 +0100 Subject: [PATCH 026/143] Add rest of style guide --- README.md | 290 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 279 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e67e4d172d..1a1c5e30b1 100644 --- a/README.md +++ b/README.md @@ -43,17 +43,17 @@ Other Style Guides 1. [Accessors](#accessors) 1. [Events](#events) 1. [jQuery](#jquery) - 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) #TBD - 1. [ECMAScript 6 Styles](#ecmascript-6-styles) #TBD - 1. [Testing](#testing) #TBD - 1. [Performance](#performance) #TBD - 1. [Resources](#resources) #TBD - 1. [In the Wild](#in-the-wild) #TBD - 1. [Translation](#translation) #TBD - 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) #TBD - 1. [Chat With Us About JavaScript](#chat-with-us-about-javascript) #TBD - 1. [Contributors](#contributors) #TBD - 1. [License](#license) #TBD + 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) + 1. [ECMAScript 6 Styles](#ecmascript-6-styles) + 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 @@ -2085,4 +2085,272 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** + +## ECMAScript 5 Compatibility + + - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). + +**[⬆ back to top](#table-of-contents)** + + +## ECMAScript 6 Styles + + - [27.1](#27.1) 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 + + - [28.1](#28.1) **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 + +**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** + + - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) + +**Tools** + + - Code Style Linters + + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) + + [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 Style Guides** + + - [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/) + +**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: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - 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 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) + - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) + - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) + - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) + - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/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) + - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) + - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) + - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) + - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) + - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) + - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) + - **General Electric**: [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) + - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) + - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) + - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) + - **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) + - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/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) + - **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) + - **Springload**: [springload/javascript](https://github.com/springload/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) + - **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) + +**[⬆ back to top](#table-of-contents)** + + +## Translation + + This style guide is also available in other languages: + + - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) + - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) + - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) + - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/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) + - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) + - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) + - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) + - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) + - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) + - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) + - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) + - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) + - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) + + +## The JavaScript Style Guide Guide + + - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) + + +## Chat With Us About JavaScript + + - Find us on [gitter](https://gitter.im/airbnb/javascript). + + +## Contributors + + - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) + + +## License + +(The MIT License) + +Copyright (c) 2014 Airbnb + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +**[⬆ back to top](#table-of-contents)** + + +## Amendments + +We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. + # } From c3d909f9cb02c07c84c8f1470c4348611d0b8398 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 8 Feb 2016 12:48:19 +0100 Subject: [PATCH 027/143] Add small section about using ES6 in place of underscore / lodash --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a1c5e30b1..fab3143a26 100644 --- a/README.md +++ b/README.md @@ -2111,6 +2111,8 @@ Other Style Guides 1. [Iterators and Generators](#iterators-and-generators) 1. [Modules](#modules) + - [27.2](#27.2) Khan Academy has a nice section in their [Javascript styleguide](https://github.com/Khan/style-guides/blob/master/style/javascript.md) that discusses various ways to [accomplish tasks in ES6 rather than using underscore/lodash](https://github.com/Khan/style-guides/blob/master/style/javascript.md#dont-use-underscore). + **[⬆ back to top](#table-of-contents)** From 8b15fcc302dbe5fbf118484435771d77f1e79695 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Mon, 8 Feb 2016 12:48:45 +0100 Subject: [PATCH 028/143] Remove unnecessary sections --- README.md | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/README.md b/README.md index fab3143a26..cbfa4c8d1e 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,6 @@ Other Style Guides 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) @@ -2233,6 +2230,7 @@ Other Style Guides - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) + - **Ascribe**: You're reading it! - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) @@ -2288,36 +2286,6 @@ Other Style Guides **[⬆ back to top](#table-of-contents)** -## Translation - - This style guide is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) - - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) - - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/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) - - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) - - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - - -## Chat With Us About JavaScript - - - Find us on [gitter](https://gitter.im/airbnb/javascript). - - ## Contributors - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) From 57c14f23d95d9bcf6074c7011ea4c8873491485a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Mar 2016 15:21:55 +0100 Subject: [PATCH 029/143] Rm README-backup.md as styleguide was completed --- README-backup.md | 2254 ---------------------------------------------- 1 file changed, 2254 deletions(-) delete mode 100644 README-backup.md diff --git a/README-backup.md b/README-backup.md deleted file mode 100644 index c95fbfc734..0000000000 --- a/README-backup.md +++ /dev/null @@ -1,2254 +0,0 @@ -# ~~Airbnb~~ ascribe JavaScript Style Guide() { - -## Introduction -At ascribe we write a lot of JavaScript and value quality code. -Since all of us liked [Airbnb's JavaScript Style Guide](https://github.com/airbnb/javascript), we figured that we can just fork it and change it to our needs. - -## Approach -As we want everyone in the team to be able to take part in the creation of this style guide, we decided to have it reviewed and transformed to our specific needs. -This is why we're going to remove all the contents of this document, to add them bit-by-bit again through a process of pull-requests and reviews. -Depending on how fast the review will be, every other day there will be a pull a new pull request for everyone to read and comment on. - -As for adjusting the linters, we still need to figure out a way on how to change them efficiently. So if you have suggestions, come forward. - - -Other Style Guides - - [ES5](es5/) - - [React](react/) - -## 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) - 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. [Events](#events) - 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) - 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 - - - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. - - + `string` - + `number` - + `boolean` - + `null` - + `undefined` - - ```javascript - const foo = 1; - let bar = foo; - - bar = 9; - - console.log(foo, bar); // => 1, 9 - ``` - - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. - - + `object` - + `array` - + `function` - - ```javascript - const foo = [1, 2]; - const bar = foo; - - bar[0] = 9; - - console.log(foo[0], bar[0]); // => 9, 9 - ``` - -**[⬆ back to top](#table-of-contents)** - -## References - - - [2.1](#2.1) 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; - ``` - - - [2.2](#2.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; - } - ``` - - - [2.3](#2.3) 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 - - - [3.1](#3.1) Use the literal syntax for object creation. - - ```javascript - // bad - const item = new Object(); - - // good - const item = {}; - ``` - - - [3.2](#3.2) If your code will be executed in browsers in script context, 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). It’s OK to use them in ES6 modules and server-side code. - - ```javascript - // bad - const superman = { - default: { clark: 'kent' }, - private: true, - }; - - // good - const superman = { - defaults: { clark: 'kent' }, - hidden: true, - }; - ``` - - - [3.3](#3.3) Use readable synonyms in place of reserved words. - - ```javascript - // bad - const superman = { - class: 'alien', - }; - - // bad - const superman = { - klass: 'alien', - }; - - // good - const superman = { - type: 'alien', - }; - ``` - - - - [3.4](#3.4) 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, - }; - ``` - - - - [3.5](#3.5) 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; - }, - }; - ``` - - - - [3.6](#3.6) 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, - }; - ``` - - - [3.7](#3.7) 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, - twoJediWalkIntoACantina: 2, - lukeSkywalker, - episodeThree: 3, - mayTheFourth: 4, - anakinSkywalker, - }; - - // good - const obj = { - lukeSkywalker, - anakinSkywalker, - episodeOne: 1, - twoJediWalkIntoACantina: 2, - episodeThree: 3, - mayTheFourth: 4, - }; - ``` - -**[⬆ back to top](#table-of-contents)** - -## Arrays - - - [4.1](#4.1) Use the literal syntax for array creation. - - ```javascript - // bad - const items = new Array(); - - // good - const items = []; - ``` - - - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. - - ```javascript - const someStack = []; - - // bad - someStack[someStack.length] = 'abracadabra'; - - // good - someStack.push('abracadabra'); - ``` - - - - [4.3](#4.3) Use array spreads `...` to copy arrays. - - ```javascript - // bad - const len = items.length; - const itemsCopy = []; - let i; - - for (i = 0; i < len; i++) { - itemsCopy[i] = items[i]; - } - - // good - const itemsCopy = [...items]; - ``` - - [4.4](#4.4) To convert an array-like object to an array, use Array#from. - - ```javascript - const foo = document.querySelectorAll('.foo'); - const nodes = Array.from(foo); - ``` - -**[⬆ back to top](#table-of-contents)** - -## Destructuring - - - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. - - > Why? Destructuring saves you from creating temporary references for those properties. - - ```javascript - // 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}`; - } - ``` - - - [5.2](#5.2) Use array destructuring. - - ```javascript - const arr = [1, 2, 3, 4]; - - // bad - const first = arr[0]; - const second = arr[1]; - - // good - const [first, second] = arr; - ``` - - - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. - - > Why? You can add new properties over time or change the order of things without breaking call sites. - - ```javascript - // bad - 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 - - - [6.1](#6.1) Use single quotes `''` for strings. - - ```javascript - // bad - const name = "Capt. Janeway"; - - // good - const name = 'Capt. Janeway'; - ``` - - - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. - - [6.3](#6.3) 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 - 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 - 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 - 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.'; - ``` - - - - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. - - > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. - - ```javascript - // bad - function sayHi(name) { - return 'How are you, ' + name + '?'; - } - - // bad - function sayHi(name) { - return ['How are you, ', name, '?'].join(); - } - - // good - function sayHi(name) { - return `How are you, ${name}?`; - } - ``` - - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. - -**[⬆ back to top](#table-of-contents)** - - -## Functions - - - [7.1](#7.1) 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 - // bad - const foo = function () { - }; - - // good - function foo() { - } - ``` - - - [7.2](#7.2) Function expressions: - - ```javascript - // immediately-invoked function expression (IIFE) - (() => { - console.log('Welcome to the Internet. Please follow me.'); - })(); - ``` - - - [7.3](#7.3) 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. - - [7.4](#7.4) **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 - let test; - if (currentUser) { - test = () => { - console.log('Yup.'); - }; - } - ``` - - - [7.5](#7.5) 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... - } - ``` - - - - [7.6](#7.6) 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(''); - } - ``` - - - - [7.7](#7.7) 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 = {}) { - // ... - } - ``` - - - [7.8](#7.8) Avoid side effects with default parameters. - - > Why? They are confusing to reason about. - - ```javascript - var b = 1; - // bad - function count(a = b++) { - console.log(a); - } - count(); // 1 - count(); // 2 - count(3); // 3 - count(); // 3 - ``` - - - [7.9](#7.9) Always put default parameters last. - - ```javascript - // bad - function handleThings(opts = {}, name) { - // ... - } - - // good - function handleThings(name, opts = {}) { - // ... - } - ``` - -- [7.10](#7.10) Never use the Function constructor to create a new function. - - > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. - - ```javascript - // bad - var add = new Function('a', 'b', 'return a + b'); - - // still bad - var subtract = Function('a', 'b', 'return a - b'); - ``` - -**[⬆ back to top](#table-of-contents)** - -## Arrow Functions - - - [8.1](#8.1) 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) { - const y = x + 1; - return x * y; - }); - - // good - [1, 2, 3].map((x) => { - const y = x + 1; - return x * y; - }); - ``` - - - [8.2](#8.2) If the function body consists of a single expression, feel free to omit the braces and use the implicit return. Otherwise 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(number => `A string containing the ${number}.`); - - // bad - [1, 2, 3].map(number => { - const nextNumber = number + 1; - `A string containing the ${nextNumber}.`; - }); - - // good - [1, 2, 3].map(number => { - const nextNumber = number + 1; - return `A string containing the ${nextNumber}.`; - }); - ``` - - - [8.3](#8.3) In case the expression spans over multiple lines, wrap it in parentheses for better readability. - - > Why? It shows clearly where the function starts and ends. - - ```js - // bad - [1, 2, 3].map(number => 'As time went by, the string containing the ' + - `${number} became much longer. So we needed to break it over multiple ` + - 'lines.' - ); - - // good - [1, 2, 3].map(number => ( - `As time went by, the string containing the ${number} became much ` + - 'longer. So we needed to break it over multiple lines.' - )); - ``` - - - - [8.4](#8.4) If your function only takes a single argument, feel free to omit the parentheses. - - > Why? Less visual clutter. - - ```js - // good - [1, 2, 3].map(x => x * x); - - // good - [1, 2, 3].reduce((y, x) => x + y); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Constructors - - - [9.1](#9.1) 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; - } - } - ``` - - - [9.2](#9.2) 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]; - } - } - ``` - - - [9.3](#9.3) 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); - ``` - - - - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. - - ```javascript - class Jedi { - constructor(options = {}) { - this.name = options.name || 'no name'; - } - - getName() { - return this.name; - } - - toString() { - return `Jedi - ${this.getName()}`; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Modules - - - [10.1](#10.1) 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; - ``` - - - [10.2](#10.2) 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'; - ``` - - - [10.3](#10.3) And do not export directly from an import. - - > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. - - ```javascript - // bad - // filename es6.js - export { es6 as default } from './airbnbStyleGuide'; - - // good - // filename es6.js - import { es6 } from './AirbnbStyleGuide'; - export default es6; - ``` - -**[⬆ back to top](#table-of-contents)** - -## Iterators and Generators - - - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. - - > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. - - ```javascript - const numbers = [1, 2, 3, 4, 5]; - - // bad - let sum = 0; - for (let num of numbers) { - sum += num; - } - - sum === 15; - - // good - let sum = 0; - numbers.forEach((num) => sum += num); - sum === 15; - - // best (use the functional force) - const sum = numbers.reduce((total, num) => total + num, 0); - sum === 15; - ``` - - - [11.2](#11.2) Don't use generators for now. - - > Why? They don't transpile well to ES5. - -**[⬆ back to top](#table-of-contents)** - - -## Properties - - - [12.1](#12.1) Use dot notation when accessing properties. - - ```javascript - const luke = { - jedi: true, - age: 28, - }; - - // bad - const isJedi = luke['jedi']; - - // good - const isJedi = luke.jedi; - ``` - - - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. - - ```javascript - const luke = { - jedi: true, - age: 28, - }; - - function getProp(prop) { - return luke[prop]; - } - - const isJedi = getProp('jedi'); - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Variables - - - [13.1](#13.1) 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 - const superPower = new SuperPower(); - ``` - - - [13.2](#13.2) 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 - const items = getItems(), - goSportsTeam = true, - dragonball = 'z'; - - // bad - // (compare to above, and try to spot the mistake) - const items = getItems(), - goSportsTeam = true; - dragonball = 'z'; - - // good - const items = getItems(); - const goSportsTeam = true; - const dragonball = 'z'; - ``` - - - [13.3](#13.3) 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 - let i, len, dragonball, - items = getItems(), - goSportsTeam = true; - - // bad - let i; - const items = getItems(); - let dragonball; - const goSportsTeam = true; - let len; - - // good - const goSportsTeam = true; - const items = getItems(); - let dragonball; - let i; - let length; - ``` - - - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. - - > Why? `let` and `const` are block scoped and not function scoped. - - ```javascript - // good - function() { - test(); - console.log('doing stuff..'); - - //..other stuff.. - - const name = getName(); - - if (name === 'test') { - return false; - } - - return name; - } - - // bad - unnecessary function call - function(hasName) { - const name = getName(); - - if (!hasName) { - return false; - } - - this.setFirstName(name); - - return true; - } - - // good - function(hasName) { - if (!hasName) { - return false; - } - - const name = getName(); - this.setFirstName(name); - - return true; - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Hoisting - - - [14.1](#14.1) `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 - // 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() { - 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; - } - ``` - - - [14.2](#14.2) 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'); - }; - } - ``` - - - [14.3](#14.3) 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'); - } - } - ``` - - - [14.4](#14.4) 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 - - - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. - - [15.2](#15.2) Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract 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 - } - ``` - - - [15.3](#15.3) Use shortcuts. - - ```javascript - // bad - if (name !== '') { - // ...stuff... - } - - // good - if (name) { - // ...stuff... - } - - // bad - if (collection.length > 0) { - // ...stuff... - } - - // good - if (collection.length) { - // ...stuff... - } - ``` - - - [15.4](#15.4) 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 - - - [16.1](#16.1) 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; - } - ``` - - - [16.2](#16.2) 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 - - - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. - - ```javascript - // bad - // make() returns a new element - // based on the passed in tag name - // - // @param {String} tag - // @return {Element} element - function make(tag) { - - // ...stuff... - - return element; - } - - // good - /** - * make() returns a new element - * based on the passed in tag name - * - * @param {String} tag - * @return {Element} element - */ - function make(tag) { - - // ...stuff... - - return element; - } - ``` - - - [17.2](#17.2) 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 - const active = true; // is current tab - - // good - // is current tab - const active = true; - - // bad - function getType() { - console.log('fetching type...'); - // set the default type to 'no type' - const type = this._type || 'no type'; - - return type; - } - - // good - function getType() { - console.log('fetching type...'); - - // set the default type to 'no type' - const type = this._type || 'no type'; - - return type; - } - ``` - - - [17.3](#17.3) 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`. - - - [17.4](#17.4) Use `// FIXME:` to annotate problems. - - ```javascript - class Calculator extends Abacus { - constructor() { - super(); - - // FIXME: shouldn't use a global here - total = 0; - } - } - ``` - - - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. - - ```javascript - class Calculator extends Abacus { - constructor() { - super(); - - // TODO: total should be configurable by an options param - this.total = 0; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Whitespace - - - [18.1](#18.1) Use soft tabs set to 2 spaces. - - ```javascript - // bad - function() { - ∙∙∙∙const name; - } - - // bad - function() { - ∙const name; - } - - // good - function() { - ∙∙const name; - } - ``` - - - [18.2](#18.2) 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', - }); - ``` - - - [18.3](#18.3) 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!'); - } - ``` - - - [18.4](#18.4) Set off operators with spaces. - - ```javascript - // bad - const x=y+5; - - // good - const x = y + 5; - ``` - - - [18.5](#18.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);↵ - ``` - - - [18.6](#18.6) 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 - 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 - const 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); - ``` - - - [18.7](#18.7) 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 - const obj = { - foo() { - }, - bar() { - }, - }; - return obj; - - // good - const obj = { - foo() { - }, - - bar() { - }, - }; - - return obj; - - // bad - const arr = [ - function foo() { - }, - function bar() { - }, - ]; - return arr; - - // good - const arr = [ - function foo() { - }, - - function bar() { - }, - ]; - - return arr; - ``` - - -**[⬆ back to top](#table-of-contents)** - -## Commas - - - [19.1](#19.1) Leading commas: **Nope.** - - ```javascript - // bad - const story = [ - once - , upon - , aTime - ]; - - // good - const story = [ - once, - upon, - aTime, - ]; - - // bad - const hero = { - firstName: 'Ada' - , lastName: 'Lovelace' - , birthYear: 1815 - , superPower: 'computers' - }; - - // good - const hero = { - firstName: 'Ada', - lastName: 'Lovelace', - birthYear: 1815, - superPower: 'computers', - }; - ``` - - - [19.2](#19.2) Additional trailing comma: **Yup.** - - > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers. - - ```javascript - // bad - git diff without trailing comma - const hero = { - firstName: 'Florence', - - lastName: 'Nightingale' - + lastName: 'Nightingale', - + inventorOf: ['coxcomb graph', 'modern nursing'] - }; - - // good - git diff with trailing comma - const hero = { - firstName: 'Florence', - lastName: 'Nightingale', - + inventorOf: ['coxcomb chart', 'modern nursing'], - }; - - // bad - const hero = { - firstName: 'Dana', - lastName: 'Scully' - }; - - const heroes = [ - 'Batman', - 'Superman' - ]; - - // good - const hero = { - firstName: 'Dana', - lastName: 'Scully', - }; - - const heroes = [ - 'Batman', - 'Superman', - ]; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Semicolons - - - [20.1](#20.1) **Yup.** - - ```javascript - // bad - (function() { - const name = 'Skywalker' - return name - })() - - // good - (() => { - const name = 'Skywalker'; - return name; - })(); - - // good (guards against the function becoming an argument when two files with IIFEs are concatenated) - ;(() => { - const name = 'Skywalker'; - return name; - })(); - ``` - - [Read more](http://stackoverflow.com/a/7365214/1712802). - -**[⬆ back to top](#table-of-contents)** - - -## Type Casting & Coercion - - - [21.1](#21.1) Perform type coercion at the beginning of the statement. - - [21.2](#21.2) Strings: - - ```javascript - // => this.reviewScore = 9; - - // bad - const totalScore = this.reviewScore + ''; - - // good - const totalScore = String(this.reviewScore); - ``` - - - [21.3](#21.3) Numbers: Use `Number` for type casting and `parseInt` always with a radix for parsing strings. - - ```javascript - const inputValue = '4'; - - // bad - const val = new Number(inputValue); - - // bad - const val = +inputValue; - - // bad - const val = inputValue >> 0; - - // bad - const val = parseInt(inputValue); - - // good - const val = Number(inputValue); - - // good - const val = parseInt(inputValue, 10); - ``` - - - [21.4](#21.4) 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. - */ - const val = inputValue >> 0; - ``` - - - [21.5](#21.5) **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 - ``` - - - [21.6](#21.6) Booleans: - - ```javascript - const age = 0; - - // bad - const hasAge = new Boolean(age); - - // good - const hasAge = Boolean(age); - - // good - const hasAge = !!age; - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Naming Conventions - - - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. - - ```javascript - // bad - function q() { - // ...stuff... - } - - // good - function query() { - // ..stuff.. - } - ``` - - - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. - - ```javascript - // bad - const OBJEcttsssss = {}; - const this_is_my_object = {}; - function c() {} - - // good - const thisIsMyObject = {}; - function thisIsMyFunction() {} - ``` - - - [22.3](#22.3) Use PascalCase when naming constructors or classes. - - ```javascript - // bad - function user(options) { - this.name = options.name; - } - - const bad = new user({ - name: 'nope', - }); - - // good - class User { - constructor(options) { - this.name = options.name; - } - } - - const good = new User({ - name: 'yup', - }); - ``` - - - [22.4](#22.4) Use a leading underscore `_` when naming private properties. - - ```javascript - // bad - this.__firstName__ = 'Panda'; - this.firstName_ = 'Panda'; - - // good - this._firstName = 'Panda'; - ``` - - - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. - - ```javascript - // bad - function foo() { - const self = this; - return function() { - console.log(self); - }; - } - - // bad - function foo() { - const that = this; - return function() { - console.log(that); - }; - } - - // good - function foo() { - return () => { - console.log(this); - }; - } - ``` - - - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. - ```javascript - // file contents - class CheckBox { - // ... - } - export default CheckBox; - - // in some other file - // bad - import CheckBox from './checkBox'; - - // bad - import CheckBox from './check_box'; - - // good - import CheckBox from './CheckBox'; - ``` - - - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. - - ```javascript - function makeStyleGuide() { - } - - export default makeStyleGuide; - ``` - - - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. - - ```javascript - const AirbnbStyleGuide = { - es6: { - } - }; - - export default AirbnbStyleGuide; - ``` - - -**[⬆ back to top](#table-of-contents)** - - -## Accessors - - - [23.1](#23.1) Accessor functions for properties are not required. - - [23.2](#23.2) 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); - ``` - - - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. - - ```javascript - // bad - if (!dragon.age()) { - return false; - } - - // good - if (!dragon.hasAge()) { - return false; - } - ``` - - - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. - - ```javascript - class Jedi { - constructor(options = {}) { - const lightsaber = options.lightsaber || 'blue'; - this.set('lightsaber', lightsaber); - } - - set(key, val) { - this[key] = val; - } - - get(key) { - return this[key]; - } - } - ``` - -**[⬆ back to top](#table-of-contents)** - - -## Events - - - [24.1](#24.1) 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: - - ```javascript - // bad - $(this).trigger('listingUpdated', listing.id); - - ... - - $(this).on('listingUpdated', function(e, listingId) { - // do something with listingId - }); - ``` - - prefer: - - ```javascript - // good - $(this).trigger('listingUpdated', { listingId: listing.id }); - - ... - - $(this).on('listingUpdated', function(e, data) { - // do something with data.listingId - }); - ``` - - **[⬆ back to top](#table-of-contents)** - - -## jQuery - - - [25.1](#25.1) Prefix jQuery object variables with a `$`. - - ```javascript - // bad - const sidebar = $('.sidebar'); - - // good - const $sidebar = $('.sidebar'); - - // good - const $sidebarBtn = $('.sidebar-btn'); - ``` - - - [25.2](#25.2) Cache jQuery lookups. - - ```javascript - // bad - function setSidebar() { - $('.sidebar').hide(); - - // ...stuff... - - $('.sidebar').css({ - 'background-color': 'pink' - }); - } - - // good - function setSidebar() { - const $sidebar = $('.sidebar'); - $sidebar.hide(); - - // ...stuff... - - $sidebar.css({ - 'background-color': 'pink' - }); - } - ``` - - - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) - - [25.4](#25.4) 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 - - - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). - -**[⬆ back to top](#table-of-contents)** - -## ECMAScript 6 Styles - - - [27.1](#27.1) 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 - - - [28.1](#28.1) **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 - -**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** - - - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) - -**Tools** - - - Code Style Linters - + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) - + [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 Style Guides** - - - [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/) - -**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: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - 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 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) - - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) - - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) - - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) - - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) - - **ComparaOnline**: [comparaonline/javascript](https://github.com/comparaonline/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) - - **Ecosia**: [ecosia/javascript](https://github.com/ecosia/javascript) - - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) - - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) - - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) - - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) - - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) - - **General Electric**: [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) - - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) - - **HubSpot**: [HubSpot/javascript](https://github.com/HubSpot/javascript) - - **Hyper**: [hyperoslo/javascript-playbook](https://github.com/hyperoslo/javascript-playbook/blob/master/style.md) - - **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) - - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/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) - - **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) - - **Springload**: [springload/javascript](https://github.com/springload/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) - - **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) - -**[⬆ back to top](#table-of-contents)** - -## Translation - - This style guide is also available in other languages: - - - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) - - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) - - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) - - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese (Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/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) - - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) - - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) - - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) - - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) - - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) - - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) - - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) - - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - -## Chat With Us About JavaScript - - - Find us on [gitter](https://gitter.im/airbnb/javascript). - -## Contributors - - - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) - - -## License - -(The MIT License) - -Copyright (c) 2014 Airbnb - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -**[⬆ back to top](#table-of-contents)** - -## Amendments - -We encourage you to fork this guide and change the rules to fit your team's style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts. - -# }; From 27c9c44f32b59762155adaf8bcf04a131e215938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Tue, 1 Mar 2016 15:34:45 +0100 Subject: [PATCH 030/143] Readd React Styleguide --- react/README-backup.md | 315 ---------------------------------------- react/README.md | 318 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 307 insertions(+), 326 deletions(-) delete mode 100644 react/README-backup.md diff --git a/react/README-backup.md b/react/README-backup.md deleted file mode 100644 index dd5592f4ed..0000000000 --- a/react/README-backup.md +++ /dev/null @@ -1,315 +0,0 @@ -# Airbnb React/JSX Style Guide - -*A mostly reasonable approach to React and JSX* - -## Table of Contents - - 1. [Basic Rules](#basic-rules) - 1. [Naming](#naming) - 1. [Declaration](#declaration) - 1. [Alignment](#alignment) - 1. [Quotes](#quotes) - 1. [Spacing](#spacing) - 1. [Props](#props) - 1. [Parentheses](#parentheses) - 1. [Tags](#tags) - 1. [Methods](#methods) - 1. [Ordering](#ordering) - -## Basic Rules - - - Only include one React component per file. - - Always use JSX syntax. - - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. - -## Class vs React.createClass - - - Use class extends React.Component unless you have a very good reason to use mixins. - - ```javascript - // bad - const Listing = React.createClass({ - render() { - return
    ; - } - }); - - // good - class Listing extends React.Component { - render() { - return
    ; - } - } - ``` - -## Naming - - - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. - - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: - ```javascript - // bad - const reservationCard = require('./ReservationCard'); - - // good - const ReservationCard = require('./ReservationCard'); - - // bad - const ReservationItem = ; - - // good - const reservationItem = ; - ``` - - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: - ```javascript - // bad - const Footer = require('./Footer/Footer.jsx') - - // bad - const Footer = require('./Footer/index.jsx') - - // good - const Footer = require('./Footer') - ``` - - -## Declaration - - Do not use displayName for naming components. Instead, name the component by reference. - - ```javascript - // bad - export default React.createClass({ - displayName: 'ReservationCard', - // stuff goes here - }); - - // good - export default class ReservationCard extends React.Component { - } - ``` - -## Alignment - - Follow these alignment styles for JSX syntax - - ```javascript - // bad - - - // good - - - // if props fit in one line then keep it on the same line - - - // children get indented normally - - - - ``` - -## Quotes - - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. - - > Why? JSX attributes [can't contain escaped quotes](http://eslint.org/docs/rules/jsx-quotes), so double quotes make conjunctions like `"don't"` easier to type. - > Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention. - - ```javascript - // bad - - - // good - - - // bad - - - // good - - ``` - -## Spacing - - Always include a single space in your self-closing tag. - ```javascript - // bad - - - // very bad - - - // bad - - - // good - - ``` - -## Props - - Always use camelCase for prop names. - ```javascript - // bad - - - // good - - ``` - -## Parentheses - - Wrap JSX tags in parentheses when they span more than one line: - ```javascript - /// bad - render() { - return - - ; - } - - // good - render() { - return ( - - - - ); - } - - // good, when single line - render() { - const body =
    hello
    ; - return {body}; - } - ``` - -## Tags - - Always self-close tags that have no children. - ```javascript - // bad - - - // good - - ``` - - - If your component has multi-line properties, close its tag on a new line. - ```javascript - // bad - - - // good - - ``` - -## Methods - - Do not use underscore prefix for internal methods of a React component. - ```javascript - // bad - React.createClass({ - _onClickSubmit() { - // do stuff - } - - // other stuff - }); - - // good - class extends React.Component { - onClickSubmit() { - // do stuff - } - - // other stuff - }); - ``` - -## Ordering - - - Ordering for class extends React.Component: - - 1. constructor - 1. optional static methods - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() - 1. *getter methods for render* like getSelectReason() or getFooterContent() - 1. *Optional render methods* like renderNavigation() or renderProfilePicture() - 1. render - - - How to define propTypes, defaultProps, contextTypes, etc... - - ```javascript - import React, { Component, PropTypes } from 'react'; - - const propTypes = { - id: PropTypes.number.isRequired, - url: PropTypes.string.isRequired, - text: PropTypes.string, - }; - - const defaultProps = { - text: 'Hello World', - }; - - export default class Link extends Component { - static methodsAreOk() { - return true; - } - - render() { - return {this.props.text} - } - } - - Link.propTypes = propTypes; - Link.defaultProps = defaultProps; - ``` - - - Ordering for React.createClass: - - 1. displayName - 1. propTypes - 1. contextTypes - 1. childContextTypes - 1. mixins - 1. statics - 1. defaultProps - 1. getDefaultProps - 1. getInitialState - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() - 1. *getter methods for render* like getSelectReason() or getFooterContent() - 1. *Optional render methods* like renderNavigation() or renderProfilePicture() - 1. render - -**[⬆ back to top](#table-of-contents)** diff --git a/react/README.md b/react/README.md index f8cf4b96e5..554d0a57af 100644 --- a/react/README.md +++ b/react/README.md @@ -4,16 +4,312 @@ ## Table of Contents - 1. [Basic Rules](#basic-rules) #TBD - 1. [Naming](#naming) #TBD - 1. [Declaration](#declaration) #TBD - 1. [Alignment](#alignment) #TBD - 1. [Quotes](#quotes) #TBD - 1. [Spacing](#spacing) #TBD - 1. [Props](#props) #TBD - 1. [Parentheses](#parentheses) #TBD - 1. [Tags](#tags) #TBD - 1. [Methods](#methods) #TBD - 1. [Ordering](#ordering) #TBD + 1. [Basic Rules](#basic-rules) + 1. [Naming](#naming) + 1. [Declaration](#declaration) + 1. [Alignment](#alignment) + 1. [Quotes](#quotes) + 1. [Spacing](#spacing) + 1. [Props](#props) + 1. [Parentheses](#parentheses) + 1. [Tags](#tags) + 1. [Methods](#methods) + 1. [Ordering](#ordering) + +## Basic Rules + + - Only include one React component per file. + - Always use JSX syntax. + - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. + +## Class vs React.createClass + + - Use class extends React.Component unless you have a very good reason to use mixins. + + ```javascript + // bad + const Listing = React.createClass({ + render() { + return
    ; + } + }); + + // good + class Listing extends React.Component { + render() { + return
    ; + } + } + ``` + +## Naming + + - **Extensions**: Use `.jsx` extension for React components. + - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: + ```javascript + // bad + const reservationCard = require('./ReservationCard'); + + // good + const ReservationCard = require('./ReservationCard'); + + // bad + const ReservationItem = ; + + // good + const reservationItem = ; + ``` + + **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: + ```javascript + // bad + const Footer = require('./Footer/Footer.jsx') + + // bad + const Footer = require('./Footer/index.jsx') + + // good + const Footer = require('./Footer') + ``` + + +## Declaration + - Do not use displayName for naming components. Instead, name the component by reference. + + ```javascript + // bad + export default React.createClass({ + displayName: 'ReservationCard', + // stuff goes here + }); + + // good + export default class ReservationCard extends React.Component { + } + ``` + +## Alignment + - Follow these alignment styles for JSX syntax + + ```javascript + // bad + + + // good + + + // if props fit in one line then keep it on the same line + + + // children get indented normally + + + + ``` + +## Quotes + - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. + + > Why? JSX attributes [can't contain escaped quotes](http://eslint.org/docs/rules/jsx-quotes), so double quotes make conjunctions like `"don't"` easier to type. + > Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention. + + ```javascript + // bad + + + // good + + + // bad + + + // good + + ``` + +## Spacing + - Always include a single space in your self-closing tag. + ```javascript + // bad + + + // very bad + + + // bad + + + // good + + ``` + +## Props + - Always use camelCase for prop names. + ```javascript + // bad + + + // good + + ``` + +## Parentheses + - Wrap JSX tags in parentheses when they span more than one line: + ```javascript + /// bad + render() { + return + + ; + } + + // good + render() { + return ( + + + + ); + } + + // good, when single line + render() { + const body =
    hello
    ; + return {body}; + } + ``` + +## Tags + - Always self-close tags that have no children. + ```javascript + // bad + + + // good + + ``` + + - If your component has multi-line properties, close its tag on a new line. + ```javascript + // bad + + + // good + + ``` + +## Methods + - Do not use underscore prefix for internal methods of a React component. + ```javascript + // bad + React.createClass({ + _onClickSubmit() { + // do stuff + } + + // other stuff + }); + + // good + class extends React.Component { + onClickSubmit() { + // do stuff + } + + // other stuff + }); + ``` + +## Ordering + + - Ordering for class extends React.Component: + + 1. constructor + 1. optional static methods + 1. getChildContext + 1. componentWillMount + 1. componentDidMount + 1. componentWillReceiveProps + 1. shouldComponentUpdate + 1. componentWillUpdate + 1. componentDidUpdate + 1. componentWillUnmount + 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() + 1. *getter methods for render* like getSelectReason() or getFooterContent() + 1. *Optional render methods* like renderNavigation() or renderProfilePicture() + 1. render + + - How to define propTypes, defaultProps, contextTypes, etc... + + ```javascript + import React, { Component, PropTypes } from 'react'; + + const propTypes = { + id: PropTypes.number.isRequired, + url: PropTypes.string.isRequired, + text: PropTypes.string, + }; + + const defaultProps = { + text: 'Hello World', + }; + + export default class Link extends Component { + static methodsAreOk() { + return true; + } + + render() { + return {this.props.text} + } + } + + Link.propTypes = propTypes; + Link.defaultProps = defaultProps; + ``` + + - Ordering for React.createClass: + + 1. displayName + 1. propTypes + 1. contextTypes + 1. childContextTypes + 1. mixins + 1. statics + 1. defaultProps + 1. getDefaultProps + 1. getInitialState + 1. getChildContext + 1. componentWillMount + 1. componentDidMount + 1. componentWillReceiveProps + 1. shouldComponentUpdate + 1. componentWillUpdate + 1. componentDidUpdate + 1. componentWillUnmount + 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() + 1. *getter methods for render* like getSelectReason() or getFooterContent() + 1. *Optional render methods* like renderNavigation() or renderProfilePicture() + 1. render # } From 2045ea46114ea64ecc4285a2ff8c96e53f3c8eb9 Mon Sep 17 00:00:00 2001 From: tim Date: Wed, 13 Apr 2016 11:09:34 +0200 Subject: [PATCH 031/143] Adjust react styleguide to ascribe specs --- react/README.md | 217 ++++++++++++++++++------------------------------ 1 file changed, 83 insertions(+), 134 deletions(-) diff --git a/react/README.md b/react/README.md index 554d0a57af..97bf0ab5a6 100644 --- a/react/README.md +++ b/react/README.md @@ -18,41 +18,42 @@ ## Basic Rules - - Only include one React component per file. + - Only `default export` one React component per file. - Always use JSX syntax. - - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. + - Always use `React.createElement` + - Don't use Mixins ## Class vs React.createClass - - Use class extends React.Component unless you have a very good reason to use mixins. + - Use `React.createClass`, don't use the ES6 class syntax for now ```javascript // bad - const Listing = React.createClass({ - render() { - return
    ; - } - }); - - // good class Listing extends React.Component { - render() { - return
    ; - } + render() { + return
    ; + } } + + // good + const Listing = React.createClass({ + render() { + return
    ; + } + }); ``` ## Naming - - **Extensions**: Use `.jsx` extension for React components. - - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. + - **Extensions**: Use `.js` extension for React components. + - **Filename**: Use snake_case for filenames. E.g., `reservation_card.js`. - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: ```javascript // bad - const reservationCard = require('./ReservationCard'); + const reservationCard = require('./reservation_card'); // good - const ReservationCard = require('./ReservationCard'); + const ReservationCard = require('./reservation_card'); // bad const ReservationItem = ; @@ -61,32 +62,41 @@ const reservationItem = ; ``` - **Component Naming**: Use the filename as the component name. For example, `ReservationCard.jsx` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.jsx` as the filename and use the directory name as the component name: + **Component Naming**: Convert snake_case filename to PascalCase component name. For example, `reservation_card.js` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name: ```javascript // bad - const Footer = require('./Footer/Footer.jsx') + const Footer = require('./Footer/footer.js') // bad - const Footer = require('./Footer/index.jsx') + const Footer = require('./Footer/index.js') // good - const Footer = require('./Footer') + const Footer = require('./footer') ``` ## Declaration - - Do not use displayName for naming components. Instead, name the component by reference. + - Declare displayName for higher level components. Otherwise just name the component by reference. ```javascript // bad - export default React.createClass({ - displayName: 'ReservationCard', - // stuff goes here + const ReservationCard = React.createClass({ + displayName: 'ReservationCard', + // stuff goes here }); // good - export default class ReservationCard extends React.Component { + function ReservationCard() { + return React.createClass({ + displayName: 'ReservationCard', + // stuff goes here + }); } + + // good + const ReservationCard = React.createClass({ + // stuff goes here + }); ``` ## Alignment @@ -94,24 +104,25 @@ ```javascript // bad - + // good + superLongParam="bar" + anotherSuperLongParam="baz" /> + // if props fit in one line then keep it on the same line // children get indented normally - + superLongParam="bar" + anotherSuperLongParam="baz"> + ``` @@ -157,15 +168,13 @@ ```javascript // bad + UserName="hello" + phone_number={12345678} /> // good + userName="hello" + phoneNumber={12345678} /> ``` ## Parentheses @@ -173,24 +182,24 @@ ```javascript /// bad render() { - return - - ; + return + + ; } // good render() { - return ( - - - - ); + return ( + + + + ); } // good, when single line render() { - const body =
    hello
    ; - return {body}; + const body =
    hello
    ; + return {body}; } ``` @@ -204,90 +213,7 @@ ``` - - If your component has multi-line properties, close its tag on a new line. - ```javascript - // bad - - - // good - - ``` - -## Methods - - Do not use underscore prefix for internal methods of a React component. - ```javascript - // bad - React.createClass({ - _onClickSubmit() { - // do stuff - } - - // other stuff - }); - - // good - class extends React.Component { - onClickSubmit() { - // do stuff - } - - // other stuff - }); - ``` - ## Ordering - - - Ordering for class extends React.Component: - - 1. constructor - 1. optional static methods - 1. getChildContext - 1. componentWillMount - 1. componentDidMount - 1. componentWillReceiveProps - 1. shouldComponentUpdate - 1. componentWillUpdate - 1. componentDidUpdate - 1. componentWillUnmount - 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() - 1. *getter methods for render* like getSelectReason() or getFooterContent() - 1. *Optional render methods* like renderNavigation() or renderProfilePicture() - 1. render - - - How to define propTypes, defaultProps, contextTypes, etc... - - ```javascript - import React, { Component, PropTypes } from 'react'; - - const propTypes = { - id: PropTypes.number.isRequired, - url: PropTypes.string.isRequired, - text: PropTypes.string, - }; - - const defaultProps = { - text: 'Hello World', - }; - - export default class Link extends Component { - static methodsAreOk() { - return true; - } - - render() { - return {this.props.text} - } - } - - Link.propTypes = propTypes; - Link.defaultProps = defaultProps; - ``` - - Ordering for React.createClass: 1. displayName @@ -312,4 +238,27 @@ 1. *Optional render methods* like renderNavigation() or renderProfilePicture() 1. render + ```javascript + import React from 'react'; + + + const Link = React.createClass({ + propTypes: { + id: PropTypes.number.isRequired, + url: PropTypes.string.isRequired, + text: PropTypes.string + }, + + getDefaultProps() { + return { + text: 'Hello World' + }; + }, + + render() { + return {this.props.text} + } + }); + ``` + # } From 3eb590dd15df625b619c5a5da7afd2693437ffb4 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Wed, 13 Apr 2016 17:51:02 +0200 Subject: [PATCH 032/143] Add a few more rules and clarifications to react style guide --- react/README.md | 66 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/react/README.md b/react/README.md index 97bf0ab5a6..8dc437712d 100644 --- a/react/README.md +++ b/react/README.md @@ -20,12 +20,13 @@ - Only `default export` one React component per file. - Always use JSX syntax. - - Always use `React.createElement` - - Don't use Mixins + - Use `React.createElement` instead of `class extends React.Component` + - Prefer stateless components over stateful components + - Don't use mixins ## Class vs React.createClass - - Use `React.createClass`, don't use the ES6 class syntax for now + - Use `React.createClass`; don't use the ES6 class syntax for now ```javascript // bad @@ -62,16 +63,34 @@ const reservationItem = ; ``` - **Component Naming**: Convert snake_case filename to PascalCase component name. For example, `reservation_card.js` should have a reference name of `ReservationCard`. However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name: + **Component Naming**: Convert snake_case filename to PascalCase component name. For example, `reservation_card.js` should have a reference name of `ReservationCard`. ```javascript // bad - const Footer = require('./Footer/footer.js') + const Footer = require('./footer_component.js'); + // good + const FooterComponent = require('./footer_component.js'); + ``` + + However, for root components of a directory, use `index.js` as the filename and use the directory name as the component name: + ```javascript // bad - const Footer = require('./Footer/index.js') + const Footer = require('./footer/footer.js'); + + // bad + const FooterDir = require('./footer/index.js'); // good - const Footer = require('./footer') + const Footer = require('./footer/index.js'); + + // better + const Footer = require('./footer'); + ``` + + **Note**: We typically allow our module loaders to resolve `.js` files without specifying the extension, so imports without the extension will also work (and are preferred): + ```javascript + const Footer = require('./footer'); // actual file is footer.js + const Footer = require('./footer/index'); // actual file is index.js ``` @@ -168,13 +187,28 @@ ```javascript // bad + phone_number={12345678} + UserName="hello" /> // good + + ``` + + - Always specify the props in alphabetical order, and put shorthand boolean props before props whose values are explicitly declared + ```javascript + // bad + phoneNumber={12345678} + hidden /> + + // good +