├── .gitignore ├── packages └── eslint-config-airbnb │ ├── index.js │ └── package.json ├── linters ├── README.md └── .eslintrc ├── package.json ├── react └── README.md ├── es5 └── README.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/index.js: -------------------------------------------------------------------------------- 1 | var resolve = require('resolve'); 2 | var stripComments = require('strip-json-comments'); 3 | var fs = require('fs'); 4 | 5 | // you could do this all at once if you wanted to look cool 6 | var filename = resolve.sync('airbnb-style/linters/.eslintrc'); 7 | var data = fs.readFileSync(filename, {encoding: 'utf-8'}); 8 | var dataWithoutComments = stripComments(data); 9 | var parsed = JSON.parse(dataWithoutComments); 10 | 11 | module.exports = parsed; 12 | -------------------------------------------------------------------------------- /linters/README.md: -------------------------------------------------------------------------------- 1 | ## `.eslintrc` 2 | 3 | We are using [eslint](http://eslint.org/) to lint our ES6 code. Our `.eslintrc` requires the following NPM packages: 4 | 5 | - `eslint` 6 | - `babel-eslint` 7 | - `eslint-plugin-react` 8 | 9 | Use the same configuration in your code editor to get linting while you are writing your code. Here are some of the plugins for editors: 10 | 11 | * [RubyMine](https://plugins.jetbrains.com/plugin/7494) 12 | * [Atom](https://atom.io/packages/linter-eslint) 13 | * Sublime -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airbnb-style", 3 | "version": "2.0.0", 4 | "description": "A mostly reasonable approach to JavaScript.", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "publish-all": "npm publish && cd ./packages/eslint-config-airbnb && npm publish" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/airbnb/javascript.git" 12 | }, 13 | "keywords": [ 14 | "style guide", 15 | "lint", 16 | "airbnb", 17 | "es6", 18 | "es2015", 19 | "react", 20 | "jsx" 21 | ], 22 | "author": "Harrison Shoff (https://twitter.com/hshoff)", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/airbnb/javascript/issues" 26 | }, 27 | "homepage": "https://github.com/airbnb/javascript" 28 | } 29 | -------------------------------------------------------------------------------- /packages/eslint-config-airbnb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-config-airbnb", 3 | "version": "0.0.6", 4 | "description": "Airbnb's ESLint config, following our styleguide", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/airbnb/javascript" 12 | }, 13 | "keywords": [ 14 | "eslint", 15 | "eslintconfig", 16 | "config", 17 | "airbnb", 18 | "javascript", 19 | "styleguide" 20 | ], 21 | "author": "Jake Teton-Landis (https://twitter.com/@jitl)", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/airbnb/javascript/issues" 25 | }, 26 | "homepage": "https://github.com/airbnb/javascript", 27 | "dependencies": { 28 | "airbnb-style": "2.0.0", 29 | "babel-eslint": "3.1.7", 30 | "eslint": "0.21.2", 31 | "eslint-plugin-react": "2.3.0", 32 | "resolve": "1.1.6", 33 | "strip-json-comments": "1.0.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /react/README.md: -------------------------------------------------------------------------------- 1 | # Airbnb React/JSX Style Guide 2 | 3 | *A mostly reasonable approach to React and JSX* 4 | 5 | ## Table of Contents 6 | 7 | 1. [Basic Rules](#basic-rules) 8 | 1. [Naming](#naming) 9 | 1. [Declaration](#declaration) 10 | 1. [Alignment](#alignment) 11 | 1. [Quotes](#quotes) 12 | 1. [Spacing](#spacing) 13 | 1. [Props](#props) 14 | 1. [Parentheses](#parentheses) 15 | 1. [Tags](#tags) 16 | 1. [Methods](#methods) 17 | 1. [Ordering](#ordering) 18 | 19 | ## Basic Rules 20 | 21 | - Only include one React component per file. 22 | - Always use JSX syntax. 23 | - Do not use `React.createElement` unless you're initializing the app from a file that is not JSX. 24 | 25 | ## Class vs React.createClass 26 | 27 | - Use class extends React.Component unless you have a very good reason to use mixins. 28 | 29 | ```javascript 30 | // bad 31 | const Listing = React.createClass({ 32 | render() { 33 | return
; 34 | } 35 | }); 36 | 37 | // good 38 | class Listing extends React.Component { 39 | render() { 40 | return
; 41 | } 42 | } 43 | ``` 44 | 45 | ## Naming 46 | 47 | - **Extensions**: Use `.jsx` extension for React components. 48 | - **Filename**: Use PascalCase for filenames. E.g., `ReservationCard.jsx`. 49 | - **Reference Naming**: Use PascalCase for React components and camelCase for their instances: 50 | ```javascript 51 | // bad 52 | const reservationCard = require('./ReservationCard'); 53 | 54 | // good 55 | const ReservationCard = require('./ReservationCard'); 56 | 57 | // bad 58 | const ReservationItem = ; 59 | 60 | // good 61 | const reservationItem = ; 62 | ``` 63 | 64 | **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: 65 | ```javascript 66 | // bad 67 | const Footer = require('./Footer/Footer.jsx') 68 | 69 | // bad 70 | const Footer = require('./Footer/index.jsx') 71 | 72 | // good 73 | const Footer = require('./Footer') 74 | ``` 75 | 76 | 77 | ## Declaration 78 | - Do not use displayName for naming components. Instead, name the component by reference. 79 | 80 | ```javascript 81 | // bad 82 | export default React.createClass({ 83 | displayName: 'ReservationCard', 84 | // stuff goes here 85 | }); 86 | 87 | // good 88 | class ReservationCard extends React.Component { 89 | } 90 | 91 | export default ReservationCard; 92 | ``` 93 | 94 | ## Alignment 95 | - Follow these alignment styles for JS syntax 96 | 97 | ```javascript 98 | // bad 99 | 101 | 102 | // good 103 | 107 | 108 | // if props fit in one line then keep it on the same line 109 | 110 | 111 | // children get indented normally 112 | 116 | 117 | 118 | ``` 119 | 120 | ## Quotes 121 | - Always use double quotes (`"`) for JSX attributes, but single quotes for all other JS. 122 | ```javascript 123 | // bad 124 | 125 | 126 | // good 127 | 128 | 129 | // bad 130 | 131 | 132 | // good 133 | 134 | ``` 135 | 136 | ## Spacing 137 | - Always include a single space in your self-closing tag. 138 | ```javascript 139 | // bad 140 | 141 | 142 | // very bad 143 | 144 | 145 | // bad 146 | 148 | 149 | // good 150 | 151 | ``` 152 | 153 | ## Props 154 | - Always use camelCase for prop names. 155 | ```javascript 156 | // bad 157 | 161 | 162 | // good 163 | 167 | ``` 168 | 169 | ## Parentheses 170 | - Wrap JSX tags in parentheses when they span more than one line: 171 | ```javascript 172 | /// bad 173 | render() { 174 | return 175 | 176 | ; 177 | } 178 | 179 | // good 180 | render() { 181 | return ( 182 | 183 | 184 | 185 | ); 186 | } 187 | 188 | // good, when single line 189 | render() { 190 | const body =
hello
; 191 | return {body}; 192 | } 193 | ``` 194 | 195 | ## Tags 196 | - Always self-close tags that have no children. 197 | ```javascript 198 | // bad 199 | 200 | 201 | // good 202 | 203 | ``` 204 | 205 | - If your component has multi-line properties, close its tag on a new line. 206 | ```javascript 207 | // bad 208 | 211 | 212 | // good 213 | 217 | ``` 218 | 219 | ## Methods 220 | - Do not use underscore prefix for internal methods of a React component. 221 | ```javascript 222 | // bad 223 | React.createClass({ 224 | _onClickSubmit() { 225 | // do stuff 226 | } 227 | 228 | // other stuff 229 | }); 230 | 231 | // good 232 | class extends React.Component { 233 | onClickSubmit() { 234 | // do stuff 235 | } 236 | 237 | // other stuff 238 | }); 239 | ``` 240 | 241 | ## Ordering 242 | 243 | - Ordering for class extends React.Component: 244 | 245 | 1. constructor 246 | 1. optional static methods 247 | 1. getChildContext 248 | 1. componentWillMount 249 | 1. componentDidMount 250 | 1. componentWillReceiveProps 251 | 1. shouldComponentUpdate 252 | 1. componentWillUpdate 253 | 1. componentDidUpdate 254 | 1. componentWillUnmount 255 | 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() 256 | 1. *getter methods for render* like getSelectReason() or getFooterContent() 257 | 1. *Optional render methods* like renderNavigation() or renderProfilePicture() 258 | 1. render 259 | 260 | - How to define propTypes, defaultProps, contextTypes, etc... 261 | 262 | ```javascript 263 | import React, { Component, PropTypes } from 'react'; 264 | 265 | const propTypes = { 266 | id: PropTypes.number.isRequired, 267 | url: PropTypes.string.isRequired, 268 | text: PropTypes.string, 269 | }; 270 | 271 | const defaultProps = { 272 | text: 'Hello World', 273 | }; 274 | 275 | class Link extends Component { 276 | static methodsAreOk() { 277 | return true; 278 | } 279 | 280 | render() { 281 | return {this.props.text} 282 | } 283 | } 284 | 285 | Link.propTypes = propTypes; 286 | Link.defaultProps = defaultProps; 287 | 288 | export default Link; 289 | ``` 290 | 291 | - Ordering for React.createClass: 292 | 293 | 1. displayName 294 | 1. propTypes 295 | 1. contextTypes 296 | 1. childContextTypes 297 | 1. mixins 298 | 1. statics 299 | 1. defaultProps 300 | 1. getDefaultProps 301 | 1. getInitialState 302 | 1. getChildContext 303 | 1. componentWillMount 304 | 1. componentDidMount 305 | 1. componentWillReceiveProps 306 | 1. shouldComponentUpdate 307 | 1. componentWillUpdate 308 | 1. componentDidUpdate 309 | 1. componentWillUnmount 310 | 1. *clickHandlers or eventHandlers* like onClickSubmit() or onChangeDescription() 311 | 1. *getter methods for render* like getSelectReason() or getFooterContent() 312 | 1. *Optional render methods* like renderNavigation() or renderProfilePicture() 313 | 1. render 314 | 315 | **[⬆ back to top](#table-of-contents)** 316 | -------------------------------------------------------------------------------- /linters/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", // https://github.com/babel/babel-eslint 3 | "plugins": [ 4 | "react", // https://github.com/yannickcr/eslint-plugin-react 5 | "filenames" 6 | ], 7 | "env": { // http://eslint.org/docs/user-guide/configuring.html#specifying-environments 8 | "browser": true, // browser global variables 9 | "node": true // Node.js global variables and Node.js-specific rules 10 | }, 11 | "ecmaFeatures": { 12 | "arrowFunctions": true, 13 | "blockBindings": true, 14 | "classes": true, 15 | "defaultParams": true, 16 | "destructuring": true, 17 | "forOf": true, 18 | "generators": false, 19 | "modules": true, 20 | "objectLiteralComputedProperties": true, 21 | "objectLiteralDuplicateProperties": false, 22 | "objectLiteralShorthandMethods": true, 23 | "objectLiteralShorthandProperties": true, 24 | "spread": true, 25 | "superInFunctions": true, 26 | "templateStrings": true, 27 | "jsx": true 28 | }, 29 | "rules": { 30 | /** 31 | * Strict mode 32 | */ 33 | // babel inserts "use strict"; for us 34 | "strict": [2, "never"], // http://eslint.org/docs/rules/strict 35 | 36 | /** 37 | * ES6 38 | */ 39 | "no-var": 2, // http://eslint.org/docs/rules/no-var 40 | "prefer-const": 2, // http://eslint.org/docs/rules/prefer-const 41 | 42 | /** 43 | * Variables 44 | */ 45 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow 46 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names 47 | "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars 48 | "vars": "local", 49 | "args": "after-used" 50 | }], 51 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define 52 | 53 | /** 54 | * Possible errors 55 | */ 56 | "comma-dangle": [2, "always-multiline"], // http://eslint.org/docs/rules/comma-dangle 57 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign 58 | "no-console": 1, // http://eslint.org/docs/rules/no-console 59 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger 60 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert 61 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition 62 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys 63 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case 64 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty 65 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign 66 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast 67 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi 68 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign 69 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations 70 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp 71 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace 72 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls 73 | "no-sparse-arrays": 2, // http://eslint.org/docs/rules/no-sparse-arrays 74 | "no-unreachable": 2, // http://eslint.org/docs/rules/no-unreachable 75 | "use-isnan": 2, // http://eslint.org/docs/rules/use-isnan 76 | "block-scoped-var": 2, // http://eslint.org/docs/rules/block-scoped-var 77 | 78 | /** 79 | * Best practices 80 | */ 81 | "consistent-return": 2, // http://eslint.org/docs/rules/consistent-return 82 | "curly": [2, "multi-line"], // http://eslint.org/docs/rules/curly 83 | "default-case": 2, // http://eslint.org/docs/rules/default-case 84 | "dot-notation": [2, { // http://eslint.org/docs/rules/dot-notation 85 | "allowKeywords": true 86 | }], 87 | "eqeqeq": 2, // http://eslint.org/docs/rules/eqeqeq 88 | "guard-for-in": 2, // http://eslint.org/docs/rules/guard-for-in 89 | "no-caller": 2, // http://eslint.org/docs/rules/no-caller 90 | "no-else-return": 2, // http://eslint.org/docs/rules/no-else-return 91 | "no-eq-null": 2, // http://eslint.org/docs/rules/no-eq-null 92 | "no-eval": 2, // http://eslint.org/docs/rules/no-eval 93 | "no-extend-native": 2, // http://eslint.org/docs/rules/no-extend-native 94 | "no-extra-bind": 2, // http://eslint.org/docs/rules/no-extra-bind 95 | "no-fallthrough": 2, // http://eslint.org/docs/rules/no-fallthrough 96 | "no-floating-decimal": 2, // http://eslint.org/docs/rules/no-floating-decimal 97 | "no-implied-eval": 2, // http://eslint.org/docs/rules/no-implied-eval 98 | "no-lone-blocks": 2, // http://eslint.org/docs/rules/no-lone-blocks 99 | "no-loop-func": 2, // http://eslint.org/docs/rules/no-loop-func 100 | "no-multi-str": 2, // http://eslint.org/docs/rules/no-multi-str 101 | "no-native-reassign": 2, // http://eslint.org/docs/rules/no-native-reassign 102 | "no-new": 2, // http://eslint.org/docs/rules/no-new 103 | "no-new-func": 2, // http://eslint.org/docs/rules/no-new-func 104 | "no-new-wrappers": 2, // http://eslint.org/docs/rules/no-new-wrappers 105 | "no-octal": 2, // http://eslint.org/docs/rules/no-octal 106 | "no-octal-escape": 2, // http://eslint.org/docs/rules/no-octal-escape 107 | "no-param-reassign": 2, // http://eslint.org/docs/rules/no-param-reassign 108 | "no-proto": 2, // http://eslint.org/docs/rules/no-proto 109 | "no-redeclare": 2, // http://eslint.org/docs/rules/no-redeclare 110 | "no-return-assign": 2, // http://eslint.org/docs/rules/no-return-assign 111 | "no-script-url": 2, // http://eslint.org/docs/rules/no-script-url 112 | "no-self-compare": 2, // http://eslint.org/docs/rules/no-self-compare 113 | "no-sequences": 2, // http://eslint.org/docs/rules/no-sequences 114 | "no-throw-literal": 2, // http://eslint.org/docs/rules/no-throw-literal 115 | "no-with": 2, // http://eslint.org/docs/rules/no-with 116 | "radix": 2, // http://eslint.org/docs/rules/radix 117 | "vars-on-top": 2, // http://eslint.org/docs/rules/vars-on-top 118 | "wrap-iife": [2, "any"], // http://eslint.org/docs/rules/wrap-iife 119 | "yoda": 2, // http://eslint.org/docs/rules/yoda 120 | 121 | /** 122 | * Style 123 | */ 124 | "indent": [2, 2], // http://eslint.org/docs/rules/indent 125 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style 126 | "1tbs", { 127 | "allowSingleLine": true 128 | }], 129 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase 130 | "properties": "never" 131 | }], 132 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing 133 | "before": false, 134 | "after": true 135 | }], 136 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style 137 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last 138 | "func-names": 1, // http://eslint.org/docs/rules/func-names 139 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing 140 | "beforeColon": false, 141 | "afterColon": true 142 | }], 143 | "new-cap": [0, { // http://eslint.org/docs/rules/new-cap 144 | "newIsCap": true 145 | }], 146 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines 147 | "max": 2 148 | }], 149 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary 150 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object 151 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func 152 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces 153 | "no-extra-parens": 0, // http://eslint.org/docs/rules/no-extra-parens 154 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle 155 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var 156 | "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks 157 | "semi": [2, "never"], // http://eslint.org/docs/rules/semi 158 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing 159 | "before": false, 160 | "after": true 161 | }], 162 | "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords 163 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks 164 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren 165 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops 166 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case 167 | "spaced-comment": 2, // http://eslint.org/docs/rules/spaced-comment 168 | "no-unused-expressions": 1, 169 | "filenames/filenames": [2, "^[a-zA-Z]+$"], 170 | 171 | /** 172 | * JSX style 173 | */ 174 | "jsx-quotes": 2, 175 | "react/display-name": 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md 176 | "react/jsx-boolean-value": [2, "always"], // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md 177 | "react/jsx-no-undef": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md 178 | "react/jsx-sort-props": 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md 179 | "react/jsx-sort-prop-types": 0, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-prop-types.md 180 | "react/jsx-uses-react": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md 181 | "react/jsx-uses-vars": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md 182 | "react/no-did-mount-set-state": [0, "allow-in-func"], // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md 183 | "react/no-did-update-set-state": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md 184 | "react/no-multi-comp": 1, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md 185 | "react/no-unknown-property": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md 186 | "react/prop-types": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md 187 | "react/react-in-jsx-scope": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md 188 | "react/self-closing-comp": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md 189 | "react/wrap-multilines": 2, // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md 190 | "react/sort-comp": [2, { // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-comp.md 191 | "order": [ 192 | "lifecycle", 193 | "/^on.+$/", 194 | "/^get.+$/", 195 | "everything-else", 196 | "rendering" 197 | ], 198 | "groups": { 199 | "lifecycle": [ 200 | "displayName", 201 | "propTypes", 202 | "contextTypes", 203 | "childContextTypes", 204 | "mixins", 205 | "statics", 206 | "defaultProps", 207 | "constructor", 208 | "getDefaultProps", 209 | "getInitialState", 210 | "getDefaultMetaState", 211 | "getDefaultState", 212 | "getChildContext", 213 | "componentWillMount", 214 | "componentDidMount", 215 | "componentWillReceiveProps", 216 | "shouldComponentUpdate", 217 | "componentWillUpdate", 218 | "componentDidUpdate", 219 | "componentWillUnmount" 220 | ], 221 | "rendering": [ 222 | "/^render.+$/", 223 | "render" 224 | ] 225 | } 226 | }] 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /es5/README.md: -------------------------------------------------------------------------------- 1 | [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 2 | 3 | # Airbnb JavaScript Style Guide() { 4 | 5 | *A mostly reasonable approach to JavaScript* 6 | 7 | 8 | ## Table of Contents 9 | 10 | 1. [Types](#types) 11 | 1. [Objects](#objects) 12 | 1. [Arrays](#arrays) 13 | 1. [Strings](#strings) 14 | 1. [Functions](#functions) 15 | 1. [Properties](#properties) 16 | 1. [Variables](#variables) 17 | 1. [Hoisting](#hoisting) 18 | 1. [Comparison Operators & Equality](#comparison-operators--equality) 19 | 1. [Blocks](#blocks) 20 | 1. [Comments](#comments) 21 | 1. [Whitespace](#whitespace) 22 | 1. [Commas](#commas) 23 | 1. [Semicolons](#semicolons) 24 | 1. [Type Casting & Coercion](#type-casting--coercion) 25 | 1. [Naming Conventions](#naming-conventions) 26 | 1. [Accessors](#accessors) 27 | 1. [Constructors](#constructors) 28 | 1. [Events](#events) 29 | 1. [Modules](#modules) 30 | 1. [jQuery](#jquery) 31 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) 32 | 1. [Testing](#testing) 33 | 1. [Performance](#performance) 34 | 1. [Resources](#resources) 35 | 1. [In the Wild](#in-the-wild) 36 | 1. [Translation](#translation) 37 | 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) 38 | 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) 39 | 1. [Contributors](#contributors) 40 | 1. [License](#license) 41 | 42 | ## Types 43 | 44 | - **Primitives**: When you access a primitive type you work directly on its value. 45 | 46 | + `string` 47 | + `number` 48 | + `boolean` 49 | + `null` 50 | + `undefined` 51 | 52 | ```javascript 53 | var foo = 1; 54 | var bar = foo; 55 | 56 | bar = 9; 57 | 58 | console.log(foo, bar); // => 1, 9 59 | ``` 60 | - **Complex**: When you access a complex type you work on a reference to its value. 61 | 62 | + `object` 63 | + `array` 64 | + `function` 65 | 66 | ```javascript 67 | var foo = [1, 2]; 68 | var bar = foo; 69 | 70 | bar[0] = 9; 71 | 72 | console.log(foo[0], bar[0]); // => 9, 9 73 | ``` 74 | 75 | **[⬆ back to top](#table-of-contents)** 76 | 77 | ## Objects 78 | 79 | - Use the literal syntax for object creation. 80 | 81 | ```javascript 82 | // bad 83 | var item = new Object(); 84 | 85 | // good 86 | var item = {}; 87 | ``` 88 | 89 | - 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). 90 | 91 | ```javascript 92 | // bad 93 | var superman = { 94 | default: { clark: 'kent' }, 95 | private: true 96 | }; 97 | 98 | // good 99 | var superman = { 100 | defaults: { clark: 'kent' }, 101 | hidden: true 102 | }; 103 | ``` 104 | 105 | - Use readable synonyms in place of reserved words. 106 | 107 | ```javascript 108 | // bad 109 | var superman = { 110 | class: 'alien' 111 | }; 112 | 113 | // bad 114 | var superman = { 115 | klass: 'alien' 116 | }; 117 | 118 | // good 119 | var superman = { 120 | type: 'alien' 121 | }; 122 | ``` 123 | 124 | **[⬆ back to top](#table-of-contents)** 125 | 126 | ## Arrays 127 | 128 | - Use the literal syntax for array creation. 129 | 130 | ```javascript 131 | // bad 132 | var items = new Array(); 133 | 134 | // good 135 | var items = []; 136 | ``` 137 | 138 | - Use Array#push instead of direct assignment to add items to an array. 139 | 140 | ```javascript 141 | var someStack = []; 142 | 143 | 144 | // bad 145 | someStack[someStack.length] = 'abracadabra'; 146 | 147 | // good 148 | someStack.push('abracadabra'); 149 | ``` 150 | 151 | - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) 152 | 153 | ```javascript 154 | var len = items.length; 155 | var itemsCopy = []; 156 | var i; 157 | 158 | // bad 159 | for (i = 0; i < len; i++) { 160 | itemsCopy[i] = items[i]; 161 | } 162 | 163 | // good 164 | itemsCopy = items.slice(); 165 | ``` 166 | 167 | - To convert an array-like object to an array, use Array#slice. 168 | 169 | ```javascript 170 | function trigger() { 171 | var args = Array.prototype.slice.call(arguments); 172 | ... 173 | } 174 | ``` 175 | 176 | **[⬆ back to top](#table-of-contents)** 177 | 178 | 179 | ## Strings 180 | 181 | - Use single quotes `''` for strings. 182 | 183 | ```javascript 184 | // bad 185 | var name = "Bob Parr"; 186 | 187 | // good 188 | var name = 'Bob Parr'; 189 | 190 | // bad 191 | var fullName = "Bob " + this.lastName; 192 | 193 | // good 194 | var fullName = 'Bob ' + this.lastName; 195 | ``` 196 | 197 | - Strings longer than 100 characters should be written across multiple lines using string concatenation. 198 | - 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). 199 | 200 | ```javascript 201 | // bad 202 | 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.'; 203 | 204 | // bad 205 | var errorMessage = 'This is a super long error that was thrown because \ 206 | of Batman. When you stop to think about how Batman had anything to do \ 207 | with this, you would get nowhere \ 208 | fast.'; 209 | 210 | // good 211 | var errorMessage = 'This is a super long error that was thrown because ' + 212 | 'of Batman. When you stop to think about how Batman had anything to do ' + 213 | 'with this, you would get nowhere fast.'; 214 | ``` 215 | 216 | - 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). 217 | 218 | ```javascript 219 | var items; 220 | var messages; 221 | var length; 222 | var i; 223 | 224 | messages = [{ 225 | state: 'success', 226 | message: 'This one worked.' 227 | }, { 228 | state: 'success', 229 | message: 'This one worked as well.' 230 | }, { 231 | state: 'error', 232 | message: 'This one did not work.' 233 | }]; 234 | 235 | length = messages.length; 236 | 237 | // bad 238 | function inbox(messages) { 239 | items = '
    '; 240 | 241 | for (i = 0; i < length; i++) { 242 | items += '
  • ' + messages[i].message + '
  • '; 243 | } 244 | 245 | return items + '
'; 246 | } 247 | 248 | // good 249 | function inbox(messages) { 250 | items = []; 251 | 252 | for (i = 0; i < length; i++) { 253 | // use direct assignment in this case because we're micro-optimizing. 254 | items[i] = '
  • ' + messages[i].message + '
  • '; 255 | } 256 | 257 | return '
      ' + items.join('') + '
    '; 258 | } 259 | ``` 260 | 261 | **[⬆ back to top](#table-of-contents)** 262 | 263 | 264 | ## Functions 265 | 266 | - Function expressions: 267 | 268 | ```javascript 269 | // anonymous function expression 270 | var anonymous = function() { 271 | return true; 272 | }; 273 | 274 | // named function expression 275 | var named = function named() { 276 | return true; 277 | }; 278 | 279 | // immediately-invoked function expression (IIFE) 280 | (function() { 281 | console.log('Welcome to the Internet. Please follow me.'); 282 | })(); 283 | ``` 284 | 285 | - 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. 286 | - **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). 287 | 288 | ```javascript 289 | // bad 290 | if (currentUser) { 291 | function test() { 292 | console.log('Nope.'); 293 | } 294 | } 295 | 296 | // good 297 | var test; 298 | if (currentUser) { 299 | test = function test() { 300 | console.log('Yup.'); 301 | }; 302 | } 303 | ``` 304 | 305 | - Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. 306 | 307 | ```javascript 308 | // bad 309 | function nope(name, options, arguments) { 310 | // ...stuff... 311 | } 312 | 313 | // good 314 | function yup(name, options, args) { 315 | // ...stuff... 316 | } 317 | ``` 318 | 319 | **[⬆ back to top](#table-of-contents)** 320 | 321 | 322 | 323 | ## Properties 324 | 325 | - Use dot notation when accessing properties. 326 | 327 | ```javascript 328 | var luke = { 329 | jedi: true, 330 | age: 28 331 | }; 332 | 333 | // bad 334 | var isJedi = luke['jedi']; 335 | 336 | // good 337 | var isJedi = luke.jedi; 338 | ``` 339 | 340 | - Use subscript notation `[]` when accessing properties with a variable. 341 | 342 | ```javascript 343 | var luke = { 344 | jedi: true, 345 | age: 28 346 | }; 347 | 348 | function getProp(prop) { 349 | return luke[prop]; 350 | } 351 | 352 | var isJedi = getProp('jedi'); 353 | ``` 354 | 355 | **[⬆ back to top](#table-of-contents)** 356 | 357 | 358 | ## Variables 359 | 360 | - 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. 361 | 362 | ```javascript 363 | // bad 364 | superPower = new SuperPower(); 365 | 366 | // good 367 | var superPower = new SuperPower(); 368 | ``` 369 | 370 | - Use one `var` declaration per variable. 371 | It's easier to add new variable declarations this way, and you never have 372 | to worry about swapping out a `;` for a `,` or introducing punctuation-only 373 | diffs. 374 | 375 | ```javascript 376 | // bad 377 | var items = getItems(), 378 | goSportsTeam = true, 379 | dragonball = 'z'; 380 | 381 | // bad 382 | // (compare to above, and try to spot the mistake) 383 | var items = getItems(), 384 | goSportsTeam = true; 385 | dragonball = 'z'; 386 | 387 | // good 388 | var items = getItems(); 389 | var goSportsTeam = true; 390 | var dragonball = 'z'; 391 | ``` 392 | 393 | - 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. 394 | 395 | ```javascript 396 | // bad 397 | var i, len, dragonball, 398 | items = getItems(), 399 | goSportsTeam = true; 400 | 401 | // bad 402 | var i; 403 | var items = getItems(); 404 | var dragonball; 405 | var goSportsTeam = true; 406 | var len; 407 | 408 | // good 409 | var items = getItems(); 410 | var goSportsTeam = true; 411 | var dragonball; 412 | var length; 413 | var i; 414 | ``` 415 | 416 | - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues. 417 | 418 | ```javascript 419 | // bad 420 | function() { 421 | test(); 422 | console.log('doing stuff..'); 423 | 424 | //..other stuff.. 425 | 426 | var name = getName(); 427 | 428 | if (name === 'test') { 429 | return false; 430 | } 431 | 432 | return name; 433 | } 434 | 435 | // good 436 | function() { 437 | var name = getName(); 438 | 439 | test(); 440 | console.log('doing stuff..'); 441 | 442 | //..other stuff.. 443 | 444 | if (name === 'test') { 445 | return false; 446 | } 447 | 448 | return name; 449 | } 450 | 451 | // bad - unnecessary function call 452 | function() { 453 | var name = getName(); 454 | 455 | if (!arguments.length) { 456 | return false; 457 | } 458 | 459 | this.setFirstName(name); 460 | 461 | return true; 462 | } 463 | 464 | // good 465 | function() { 466 | var name; 467 | 468 | if (!arguments.length) { 469 | return false; 470 | } 471 | 472 | name = getName(); 473 | this.setFirstName(name); 474 | 475 | return true; 476 | } 477 | ``` 478 | 479 | **[⬆ back to top](#table-of-contents)** 480 | 481 | 482 | ## Hoisting 483 | 484 | - Variable declarations get hoisted to the top of their scope, but their assignment does not. 485 | 486 | ```javascript 487 | // we know this wouldn't work (assuming there 488 | // is no notDefined global variable) 489 | function example() { 490 | console.log(notDefined); // => throws a ReferenceError 491 | } 492 | 493 | // creating a variable declaration after you 494 | // reference the variable will work due to 495 | // variable hoisting. Note: the assignment 496 | // value of `true` is not hoisted. 497 | function example() { 498 | console.log(declaredButNotAssigned); // => undefined 499 | var declaredButNotAssigned = true; 500 | } 501 | 502 | // The interpreter is hoisting the variable 503 | // declaration to the top of the scope, 504 | // which means our example could be rewritten as: 505 | function example() { 506 | var declaredButNotAssigned; 507 | console.log(declaredButNotAssigned); // => undefined 508 | declaredButNotAssigned = true; 509 | } 510 | ``` 511 | 512 | - Anonymous function expressions hoist their variable name, but not the function assignment. 513 | 514 | ```javascript 515 | function example() { 516 | console.log(anonymous); // => undefined 517 | 518 | anonymous(); // => TypeError anonymous is not a function 519 | 520 | var anonymous = function() { 521 | console.log('anonymous function expression'); 522 | }; 523 | } 524 | ``` 525 | 526 | - Named function expressions hoist the variable name, not the function name or the function body. 527 | 528 | ```javascript 529 | function example() { 530 | console.log(named); // => undefined 531 | 532 | named(); // => TypeError named is not a function 533 | 534 | superPower(); // => ReferenceError superPower is not defined 535 | 536 | var named = function superPower() { 537 | console.log('Flying'); 538 | }; 539 | } 540 | 541 | // the same is true when the function name 542 | // is the same as the variable name. 543 | function example() { 544 | console.log(named); // => undefined 545 | 546 | named(); // => TypeError named is not a function 547 | 548 | var named = function named() { 549 | console.log('named'); 550 | } 551 | } 552 | ``` 553 | 554 | - Function declarations hoist their name and the function body. 555 | 556 | ```javascript 557 | function example() { 558 | superPower(); // => Flying 559 | 560 | function superPower() { 561 | console.log('Flying'); 562 | } 563 | } 564 | ``` 565 | 566 | - 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/). 567 | 568 | **[⬆ back to top](#table-of-contents)** 569 | 570 | 571 | 572 | ## Comparison Operators & Equality 573 | 574 | - Use `===` and `!==` over `==` and `!=`. 575 | - Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow these simple rules: 576 | 577 | + **Objects** evaluate to **true** 578 | + **Undefined** evaluates to **false** 579 | + **Null** evaluates to **false** 580 | + **Booleans** evaluate to **the value of the boolean** 581 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** 582 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** 583 | 584 | ```javascript 585 | if ([0]) { 586 | // true 587 | // An array is an object, objects evaluate to true 588 | } 589 | ``` 590 | 591 | - Use shortcuts. 592 | 593 | ```javascript 594 | // bad 595 | if (name !== '') { 596 | // ...stuff... 597 | } 598 | 599 | // good 600 | if (name) { 601 | // ...stuff... 602 | } 603 | 604 | // bad 605 | if (collection.length > 0) { 606 | // ...stuff... 607 | } 608 | 609 | // good 610 | if (collection.length) { 611 | // ...stuff... 612 | } 613 | ``` 614 | 615 | - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. 616 | 617 | **[⬆ back to top](#table-of-contents)** 618 | 619 | 620 | ## Blocks 621 | 622 | - Use braces with all multi-line blocks. 623 | 624 | ```javascript 625 | // bad 626 | if (test) 627 | return false; 628 | 629 | // good 630 | if (test) return false; 631 | 632 | // good 633 | if (test) { 634 | return false; 635 | } 636 | 637 | // bad 638 | function() { return false; } 639 | 640 | // good 641 | function() { 642 | return false; 643 | } 644 | ``` 645 | 646 | - If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your 647 | `if` block's closing brace. 648 | 649 | ```javascript 650 | // bad 651 | if (test) { 652 | thing1(); 653 | thing2(); 654 | } 655 | else { 656 | thing3(); 657 | } 658 | 659 | // good 660 | if (test) { 661 | thing1(); 662 | thing2(); 663 | } else { 664 | thing3(); 665 | } 666 | ``` 667 | 668 | 669 | **[⬆ back to top](#table-of-contents)** 670 | 671 | 672 | ## Comments 673 | 674 | - Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. 675 | 676 | ```javascript 677 | // bad 678 | // make() returns a new element 679 | // based on the passed in tag name 680 | // 681 | // @param {String} tag 682 | // @return {Element} element 683 | function make(tag) { 684 | 685 | // ...stuff... 686 | 687 | return element; 688 | } 689 | 690 | // good 691 | /** 692 | * make() returns a new element 693 | * based on the passed in tag name 694 | * 695 | * @param {String} tag 696 | * @return {Element} element 697 | */ 698 | function make(tag) { 699 | 700 | // ...stuff... 701 | 702 | return element; 703 | } 704 | ``` 705 | 706 | - 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. 707 | 708 | ```javascript 709 | // bad 710 | var active = true; // is current tab 711 | 712 | // good 713 | // is current tab 714 | var active = true; 715 | 716 | // bad 717 | function getType() { 718 | console.log('fetching type...'); 719 | // set the default type to 'no type' 720 | var type = this._type || 'no type'; 721 | 722 | return type; 723 | } 724 | 725 | // good 726 | function getType() { 727 | console.log('fetching type...'); 728 | 729 | // set the default type to 'no type' 730 | var type = this._type || 'no type'; 731 | 732 | return type; 733 | } 734 | ``` 735 | 736 | - 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`. 737 | 738 | - Use `// FIXME:` to annotate problems. 739 | 740 | ```javascript 741 | function Calculator() { 742 | 743 | // FIXME: shouldn't use a global here 744 | total = 0; 745 | 746 | return this; 747 | } 748 | ``` 749 | 750 | - Use `// TODO:` to annotate solutions to problems. 751 | 752 | ```javascript 753 | function Calculator() { 754 | 755 | // TODO: total should be configurable by an options param 756 | this.total = 0; 757 | 758 | return this; 759 | } 760 | ``` 761 | 762 | **[⬆ back to top](#table-of-contents)** 763 | 764 | 765 | ## Whitespace 766 | 767 | - Use soft tabs set to 2 spaces. 768 | 769 | ```javascript 770 | // bad 771 | function() { 772 | ∙∙∙∙var name; 773 | } 774 | 775 | // bad 776 | function() { 777 | ∙var name; 778 | } 779 | 780 | // good 781 | function() { 782 | ∙∙var name; 783 | } 784 | ``` 785 | 786 | - Place 1 space before the leading brace. 787 | 788 | ```javascript 789 | // bad 790 | function test(){ 791 | console.log('test'); 792 | } 793 | 794 | // good 795 | function test() { 796 | console.log('test'); 797 | } 798 | 799 | // bad 800 | dog.set('attr',{ 801 | age: '1 year', 802 | breed: 'Bernese Mountain Dog' 803 | }); 804 | 805 | // good 806 | dog.set('attr', { 807 | age: '1 year', 808 | breed: 'Bernese Mountain Dog' 809 | }); 810 | ``` 811 | 812 | - 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. 813 | 814 | ```javascript 815 | // bad 816 | if(isJedi) { 817 | fight (); 818 | } 819 | 820 | // good 821 | if (isJedi) { 822 | fight(); 823 | } 824 | 825 | // bad 826 | function fight () { 827 | console.log ('Swooosh!'); 828 | } 829 | 830 | // good 831 | function fight() { 832 | console.log('Swooosh!'); 833 | } 834 | ``` 835 | 836 | - Set off operators with spaces. 837 | 838 | ```javascript 839 | // bad 840 | var x=y+5; 841 | 842 | // good 843 | var x = y + 5; 844 | ``` 845 | 846 | - End files with a single newline character. 847 | 848 | ```javascript 849 | // bad 850 | (function(global) { 851 | // ...stuff... 852 | })(this); 853 | ``` 854 | 855 | ```javascript 856 | // bad 857 | (function(global) { 858 | // ...stuff... 859 | })(this);↵ 860 | ↵ 861 | ``` 862 | 863 | ```javascript 864 | // good 865 | (function(global) { 866 | // ...stuff... 867 | })(this);↵ 868 | ``` 869 | 870 | - Use indentation when making long method chains. Use a leading dot, which 871 | emphasizes that the line is a method call, not a new statement. 872 | 873 | ```javascript 874 | // bad 875 | $('#items').find('.selected').highlight().end().find('.open').updateCount(); 876 | 877 | // bad 878 | $('#items'). 879 | find('.selected'). 880 | highlight(). 881 | end(). 882 | find('.open'). 883 | updateCount(); 884 | 885 | // good 886 | $('#items') 887 | .find('.selected') 888 | .highlight() 889 | .end() 890 | .find('.open') 891 | .updateCount(); 892 | 893 | // bad 894 | var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true) 895 | .attr('width', (radius + margin) * 2).append('svg:g') 896 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 897 | .call(tron.led); 898 | 899 | // good 900 | var leds = stage.selectAll('.led') 901 | .data(data) 902 | .enter().append('svg:svg') 903 | .classed('led', true) 904 | .attr('width', (radius + margin) * 2) 905 | .append('svg:g') 906 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 907 | .call(tron.led); 908 | ``` 909 | 910 | - Leave a blank line after blocks and before the next statement 911 | 912 | ```javascript 913 | // bad 914 | if (foo) { 915 | return bar; 916 | } 917 | return baz; 918 | 919 | // good 920 | if (foo) { 921 | return bar; 922 | } 923 | 924 | return baz; 925 | 926 | // bad 927 | var obj = { 928 | foo: function() { 929 | }, 930 | bar: function() { 931 | } 932 | }; 933 | return obj; 934 | 935 | // good 936 | var obj = { 937 | foo: function() { 938 | }, 939 | 940 | bar: function() { 941 | } 942 | }; 943 | 944 | return obj; 945 | ``` 946 | 947 | 948 | **[⬆ back to top](#table-of-contents)** 949 | 950 | ## Commas 951 | 952 | - Leading commas: **Nope.** 953 | 954 | ```javascript 955 | // bad 956 | var story = [ 957 | once 958 | , upon 959 | , aTime 960 | ]; 961 | 962 | // good 963 | var story = [ 964 | once, 965 | upon, 966 | aTime 967 | ]; 968 | 969 | // bad 970 | var hero = { 971 | firstName: 'Bob' 972 | , lastName: 'Parr' 973 | , heroName: 'Mr. Incredible' 974 | , superPower: 'strength' 975 | }; 976 | 977 | // good 978 | var hero = { 979 | firstName: 'Bob', 980 | lastName: 'Parr', 981 | heroName: 'Mr. Incredible', 982 | superPower: 'strength' 983 | }; 984 | ``` 985 | 986 | - 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)): 987 | 988 | > 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. 989 | 990 | ```javascript 991 | // bad 992 | var hero = { 993 | firstName: 'Kevin', 994 | lastName: 'Flynn', 995 | }; 996 | 997 | var heroes = [ 998 | 'Batman', 999 | 'Superman', 1000 | ]; 1001 | 1002 | // good 1003 | var hero = { 1004 | firstName: 'Kevin', 1005 | lastName: 'Flynn' 1006 | }; 1007 | 1008 | var heroes = [ 1009 | 'Batman', 1010 | 'Superman' 1011 | ]; 1012 | ``` 1013 | 1014 | **[⬆ back to top](#table-of-contents)** 1015 | 1016 | 1017 | ## Semicolons 1018 | 1019 | - **Yup.** 1020 | 1021 | ```javascript 1022 | // bad 1023 | (function() { 1024 | var name = 'Skywalker' 1025 | return name 1026 | })() 1027 | 1028 | // good 1029 | (function() { 1030 | var name = 'Skywalker'; 1031 | return name; 1032 | })(); 1033 | 1034 | // good (guards against the function becoming an argument when two files with IIFEs are concatenated) 1035 | ;(function() { 1036 | var name = 'Skywalker'; 1037 | return name; 1038 | })(); 1039 | ``` 1040 | 1041 | [Read more](http://stackoverflow.com/a/7365214/1712802). 1042 | 1043 | **[⬆ back to top](#table-of-contents)** 1044 | 1045 | 1046 | ## Type Casting & Coercion 1047 | 1048 | - Perform type coercion at the beginning of the statement. 1049 | - Strings: 1050 | 1051 | ```javascript 1052 | // => this.reviewScore = 9; 1053 | 1054 | // bad 1055 | var totalScore = this.reviewScore + ''; 1056 | 1057 | // good 1058 | var totalScore = '' + this.reviewScore; 1059 | 1060 | // bad 1061 | var totalScore = '' + this.reviewScore + ' total score'; 1062 | 1063 | // good 1064 | var totalScore = this.reviewScore + ' total score'; 1065 | ``` 1066 | 1067 | - Use `parseInt` for Numbers and always with a radix for type casting. 1068 | 1069 | ```javascript 1070 | var inputValue = '4'; 1071 | 1072 | // bad 1073 | var val = new Number(inputValue); 1074 | 1075 | // bad 1076 | var val = +inputValue; 1077 | 1078 | // bad 1079 | var val = inputValue >> 0; 1080 | 1081 | // bad 1082 | var val = parseInt(inputValue); 1083 | 1084 | // good 1085 | var val = Number(inputValue); 1086 | 1087 | // good 1088 | var val = parseInt(inputValue, 10); 1089 | ``` 1090 | 1091 | - 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. 1092 | 1093 | ```javascript 1094 | // good 1095 | /** 1096 | * parseInt was the reason my code was slow. 1097 | * Bitshifting the String to coerce it to a 1098 | * Number made it a lot faster. 1099 | */ 1100 | var val = inputValue >> 0; 1101 | ``` 1102 | 1103 | - **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: 1104 | 1105 | ```javascript 1106 | 2147483647 >> 0 //=> 2147483647 1107 | 2147483648 >> 0 //=> -2147483648 1108 | 2147483649 >> 0 //=> -2147483647 1109 | ``` 1110 | 1111 | - Booleans: 1112 | 1113 | ```javascript 1114 | var age = 0; 1115 | 1116 | // bad 1117 | var hasAge = new Boolean(age); 1118 | 1119 | // good 1120 | var hasAge = Boolean(age); 1121 | 1122 | // good 1123 | var hasAge = !!age; 1124 | ``` 1125 | 1126 | **[⬆ back to top](#table-of-contents)** 1127 | 1128 | 1129 | ## Naming Conventions 1130 | 1131 | - Avoid single letter names. Be descriptive with your naming. 1132 | 1133 | ```javascript 1134 | // bad 1135 | function q() { 1136 | // ...stuff... 1137 | } 1138 | 1139 | // good 1140 | function query() { 1141 | // ..stuff.. 1142 | } 1143 | ``` 1144 | 1145 | - Use camelCase when naming objects, functions, and instances. 1146 | 1147 | ```javascript 1148 | // bad 1149 | var OBJEcttsssss = {}; 1150 | var this_is_my_object = {}; 1151 | var o = {}; 1152 | function c() {} 1153 | 1154 | // good 1155 | var thisIsMyObject = {}; 1156 | function thisIsMyFunction() {} 1157 | ``` 1158 | 1159 | - Use PascalCase when naming constructors or classes. 1160 | 1161 | ```javascript 1162 | // bad 1163 | function user(options) { 1164 | this.name = options.name; 1165 | } 1166 | 1167 | var bad = new user({ 1168 | name: 'nope' 1169 | }); 1170 | 1171 | // good 1172 | function User(options) { 1173 | this.name = options.name; 1174 | } 1175 | 1176 | var good = new User({ 1177 | name: 'yup' 1178 | }); 1179 | ``` 1180 | 1181 | - Use a leading underscore `_` when naming private properties. 1182 | 1183 | ```javascript 1184 | // bad 1185 | this.__firstName__ = 'Panda'; 1186 | this.firstName_ = 'Panda'; 1187 | 1188 | // good 1189 | this._firstName = 'Panda'; 1190 | ``` 1191 | 1192 | - When saving a reference to `this` use `_this`. 1193 | 1194 | ```javascript 1195 | // bad 1196 | function() { 1197 | var self = this; 1198 | return function() { 1199 | console.log(self); 1200 | }; 1201 | } 1202 | 1203 | // bad 1204 | function() { 1205 | var that = this; 1206 | return function() { 1207 | console.log(that); 1208 | }; 1209 | } 1210 | 1211 | // good 1212 | function() { 1213 | var _this = this; 1214 | return function() { 1215 | console.log(_this); 1216 | }; 1217 | } 1218 | ``` 1219 | 1220 | - Name your functions. This is helpful for stack traces. 1221 | 1222 | ```javascript 1223 | // bad 1224 | var log = function(msg) { 1225 | console.log(msg); 1226 | }; 1227 | 1228 | // good 1229 | var log = function log(msg) { 1230 | console.log(msg); 1231 | }; 1232 | ``` 1233 | 1234 | - **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. 1235 | 1236 | - If your file exports a single class, your filename should be exactly the name of the class. 1237 | ```javascript 1238 | // file contents 1239 | class CheckBox { 1240 | // ... 1241 | } 1242 | module.exports = CheckBox; 1243 | 1244 | // in some other file 1245 | // bad 1246 | var CheckBox = require('./checkBox'); 1247 | 1248 | // bad 1249 | var CheckBox = require('./check_box'); 1250 | 1251 | // good 1252 | var CheckBox = require('./CheckBox'); 1253 | ``` 1254 | 1255 | **[⬆ back to top](#table-of-contents)** 1256 | 1257 | 1258 | ## Accessors 1259 | 1260 | - Accessor functions for properties are not required. 1261 | - If you do make accessor functions use getVal() and setVal('hello'). 1262 | 1263 | ```javascript 1264 | // bad 1265 | dragon.age(); 1266 | 1267 | // good 1268 | dragon.getAge(); 1269 | 1270 | // bad 1271 | dragon.age(25); 1272 | 1273 | // good 1274 | dragon.setAge(25); 1275 | ``` 1276 | 1277 | - If the property is a boolean, use isVal() or hasVal(). 1278 | 1279 | ```javascript 1280 | // bad 1281 | if (!dragon.age()) { 1282 | return false; 1283 | } 1284 | 1285 | // good 1286 | if (!dragon.hasAge()) { 1287 | return false; 1288 | } 1289 | ``` 1290 | 1291 | - It's okay to create get() and set() functions, but be consistent. 1292 | 1293 | ```javascript 1294 | function Jedi(options) { 1295 | options || (options = {}); 1296 | var lightsaber = options.lightsaber || 'blue'; 1297 | this.set('lightsaber', lightsaber); 1298 | } 1299 | 1300 | Jedi.prototype.set = function(key, val) { 1301 | this[key] = val; 1302 | }; 1303 | 1304 | Jedi.prototype.get = function(key) { 1305 | return this[key]; 1306 | }; 1307 | ``` 1308 | 1309 | **[⬆ back to top](#table-of-contents)** 1310 | 1311 | 1312 | ## Constructors 1313 | 1314 | - 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! 1315 | 1316 | ```javascript 1317 | function Jedi() { 1318 | console.log('new jedi'); 1319 | } 1320 | 1321 | // bad 1322 | Jedi.prototype = { 1323 | fight: function fight() { 1324 | console.log('fighting'); 1325 | }, 1326 | 1327 | block: function block() { 1328 | console.log('blocking'); 1329 | } 1330 | }; 1331 | 1332 | // good 1333 | Jedi.prototype.fight = function fight() { 1334 | console.log('fighting'); 1335 | }; 1336 | 1337 | Jedi.prototype.block = function block() { 1338 | console.log('blocking'); 1339 | }; 1340 | ``` 1341 | 1342 | - Methods can return `this` to help with method chaining. 1343 | 1344 | ```javascript 1345 | // bad 1346 | Jedi.prototype.jump = function() { 1347 | this.jumping = true; 1348 | return true; 1349 | }; 1350 | 1351 | Jedi.prototype.setHeight = function(height) { 1352 | this.height = height; 1353 | }; 1354 | 1355 | var luke = new Jedi(); 1356 | luke.jump(); // => true 1357 | luke.setHeight(20); // => undefined 1358 | 1359 | // good 1360 | Jedi.prototype.jump = function() { 1361 | this.jumping = true; 1362 | return this; 1363 | }; 1364 | 1365 | Jedi.prototype.setHeight = function(height) { 1366 | this.height = height; 1367 | return this; 1368 | }; 1369 | 1370 | var luke = new Jedi(); 1371 | 1372 | luke.jump() 1373 | .setHeight(20); 1374 | ``` 1375 | 1376 | 1377 | - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. 1378 | 1379 | ```javascript 1380 | function Jedi(options) { 1381 | options || (options = {}); 1382 | this.name = options.name || 'no name'; 1383 | } 1384 | 1385 | Jedi.prototype.getName = function getName() { 1386 | return this.name; 1387 | }; 1388 | 1389 | Jedi.prototype.toString = function toString() { 1390 | return 'Jedi - ' + this.getName(); 1391 | }; 1392 | ``` 1393 | 1394 | **[⬆ back to top](#table-of-contents)** 1395 | 1396 | 1397 | ## Events 1398 | 1399 | - 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: 1400 | 1401 | ```js 1402 | // bad 1403 | $(this).trigger('listingUpdated', listing.id); 1404 | 1405 | ... 1406 | 1407 | $(this).on('listingUpdated', function(e, listingId) { 1408 | // do something with listingId 1409 | }); 1410 | ``` 1411 | 1412 | prefer: 1413 | 1414 | ```js 1415 | // good 1416 | $(this).trigger('listingUpdated', { listingId : listing.id }); 1417 | 1418 | ... 1419 | 1420 | $(this).on('listingUpdated', function(e, data) { 1421 | // do something with data.listingId 1422 | }); 1423 | ``` 1424 | 1425 | **[⬆ back to top](#table-of-contents)** 1426 | 1427 | 1428 | ## Modules 1429 | 1430 | - 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) 1431 | - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export. 1432 | - Add a method called `noConflict()` that sets the exported module to the previous version and returns this one. 1433 | - Always declare `'use strict';` at the top of the module. 1434 | 1435 | ```javascript 1436 | // fancyInput/fancyInput.js 1437 | 1438 | !function(global) { 1439 | 'use strict'; 1440 | 1441 | var previousFancyInput = global.FancyInput; 1442 | 1443 | function FancyInput(options) { 1444 | this.options = options || {}; 1445 | } 1446 | 1447 | FancyInput.noConflict = function noConflict() { 1448 | global.FancyInput = previousFancyInput; 1449 | return FancyInput; 1450 | }; 1451 | 1452 | global.FancyInput = FancyInput; 1453 | }(this); 1454 | ``` 1455 | 1456 | **[⬆ back to top](#table-of-contents)** 1457 | 1458 | 1459 | ## jQuery 1460 | 1461 | - Prefix jQuery object variables with a `$`. 1462 | 1463 | ```javascript 1464 | // bad 1465 | var sidebar = $('.sidebar'); 1466 | 1467 | // good 1468 | var $sidebar = $('.sidebar'); 1469 | ``` 1470 | 1471 | - Cache jQuery lookups. 1472 | 1473 | ```javascript 1474 | // bad 1475 | function setSidebar() { 1476 | $('.sidebar').hide(); 1477 | 1478 | // ...stuff... 1479 | 1480 | $('.sidebar').css({ 1481 | 'background-color': 'pink' 1482 | }); 1483 | } 1484 | 1485 | // good 1486 | function setSidebar() { 1487 | var $sidebar = $('.sidebar'); 1488 | $sidebar.hide(); 1489 | 1490 | // ...stuff... 1491 | 1492 | $sidebar.css({ 1493 | 'background-color': 'pink' 1494 | }); 1495 | } 1496 | ``` 1497 | 1498 | - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16) 1499 | - Use `find` with scoped jQuery object queries. 1500 | 1501 | ```javascript 1502 | // bad 1503 | $('ul', '.sidebar').hide(); 1504 | 1505 | // bad 1506 | $('.sidebar').find('ul').hide(); 1507 | 1508 | // good 1509 | $('.sidebar ul').hide(); 1510 | 1511 | // good 1512 | $('.sidebar > ul').hide(); 1513 | 1514 | // good 1515 | $sidebar.find('ul').hide(); 1516 | ``` 1517 | 1518 | **[⬆ back to top](#table-of-contents)** 1519 | 1520 | 1521 | ## ECMAScript 5 Compatibility 1522 | 1523 | - Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). 1524 | 1525 | **[⬆ back to top](#table-of-contents)** 1526 | 1527 | 1528 | ## Testing 1529 | 1530 | - **Yup.** 1531 | 1532 | ```javascript 1533 | function() { 1534 | return true; 1535 | } 1536 | ``` 1537 | 1538 | **[⬆ back to top](#table-of-contents)** 1539 | 1540 | 1541 | ## Performance 1542 | 1543 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) 1544 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) 1545 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) 1546 | - [Bang Function](http://jsperf.com/bang-function) 1547 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) 1548 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) 1549 | - [Long String Concatenation](http://jsperf.com/ya-string-concat) 1550 | - Loading... 1551 | 1552 | **[⬆ back to top](#table-of-contents)** 1553 | 1554 | 1555 | ## Resources 1556 | 1557 | 1558 | **Read This** 1559 | 1560 | - [Annotated ECMAScript 5.1](http://es5.github.com/) 1561 | 1562 | **Tools** 1563 | 1564 | - Code Style Linters 1565 | + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) 1566 | + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) 1567 | 1568 | **Other Style Guides** 1569 | 1570 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) 1571 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) 1572 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) 1573 | - [JavaScript Standard Style](https://github.com/feross/standard) 1574 | 1575 | **Other Styles** 1576 | 1577 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen 1578 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen 1579 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun 1580 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman 1581 | 1582 | **Further Reading** 1583 | 1584 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll 1585 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer 1586 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz 1587 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban 1588 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock 1589 | 1590 | **Books** 1591 | 1592 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford 1593 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov 1594 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz 1595 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders 1596 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas 1597 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw 1598 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig 1599 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch 1600 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault 1601 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg 1602 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy 1603 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 1604 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov 1605 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman 1606 | - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke 1607 | - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson 1608 | 1609 | **Blogs** 1610 | 1611 | - [DailyJS](http://dailyjs.com/) 1612 | - [JavaScript Weekly](http://javascriptweekly.com/) 1613 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) 1614 | - [Bocoup Weblog](http://weblog.bocoup.com/) 1615 | - [Adequately Good](http://www.adequatelygood.com/) 1616 | - [NCZOnline](http://www.nczonline.net/) 1617 | - [Perfection Kills](http://perfectionkills.com/) 1618 | - [Ben Alman](http://benalman.com/) 1619 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 1620 | - [Dustin Diaz](http://dustindiaz.com/) 1621 | - [nettuts](http://net.tutsplus.com/?s=javascript) 1622 | 1623 | **Podcasts** 1624 | 1625 | - [JavaScript Jabber](http://devchat.tv/js-jabber/) 1626 | 1627 | 1628 | **[⬆ back to top](#table-of-contents)** 1629 | 1630 | ## In the Wild 1631 | 1632 | 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. 1633 | 1634 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 1635 | - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) 1636 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 1637 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) 1638 | - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) 1639 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) 1640 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 1641 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 1642 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) 1643 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 1644 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 1645 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) 1646 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) 1647 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 1648 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 1649 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 1650 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) 1651 | - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) 1652 | - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) 1653 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) 1654 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) 1655 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) 1656 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 1657 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 1658 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) 1659 | - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) 1660 | - **Muber**: [muber/javascript](https://github.com/muber/javascript) 1661 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) 1662 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) 1663 | - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) 1664 | - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript) 1665 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) 1666 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) 1667 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) 1668 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) 1669 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) 1670 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) 1671 | - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) 1672 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 1673 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) 1674 | - **Target**: [target/javascript](https://github.com/target/javascript) 1675 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) 1676 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) 1677 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) 1678 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) 1679 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 1680 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 1681 | 1682 | ## Translation 1683 | 1684 | This style guide is also available in other languages: 1685 | 1686 | - ![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) 1687 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 1688 | - ![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) 1689 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 1690 | - ![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) 1691 | - ![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) 1692 | - ![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) 1693 | - ![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) 1694 | - ![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) 1695 | - ![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) 1696 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 1697 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) 1698 | - ![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) 1699 | - ![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) 1700 | 1701 | ## The JavaScript Style Guide Guide 1702 | 1703 | - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 1704 | 1705 | ## Chat With Us About JavaScript 1706 | 1707 | - Find us on [gitter](https://gitter.im/airbnb/javascript). 1708 | 1709 | ## Contributors 1710 | 1711 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) 1712 | 1713 | 1714 | ## License 1715 | 1716 | (The MIT License) 1717 | 1718 | Copyright (c) 2014 Airbnb 1719 | 1720 | Permission is hereby granted, free of charge, to any person obtaining 1721 | a copy of this software and associated documentation files (the 1722 | 'Software'), to deal in the Software without restriction, including 1723 | without limitation the rights to use, copy, modify, merge, publish, 1724 | distribute, sublicense, and/or sell copies of the Software, and to 1725 | permit persons to whom the Software is furnished to do so, subject to 1726 | the following conditions: 1727 | 1728 | The above copyright notice and this permission notice shall be 1729 | included in all copies or substantial portions of the Software. 1730 | 1731 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 1732 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1733 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1734 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 1735 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 1736 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 1737 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1738 | 1739 | **[⬆ back to top](#table-of-contents)** 1740 | 1741 | # }; 1742 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | (a fork of Airbnb's Javascript Style Guide) 2 | 3 | # Strikingly ES6 JavaScript Style Guide() { 4 | 5 | *A mostly reasonable approach to JavaScript* 6 | 7 | [For Strikingly CofffeeScript guide click here](https://github.com/strikingly/coffeescript-style-guide). 8 | 9 | ## Table of Contents 10 | 11 | 1. [Types](#types) 12 | 1. [References](#references) 13 | 1. [Objects](#objects) 14 | 1. [Arrays](#arrays) 15 | 1. [Destructuring](#destructuring) 16 | 1. [Strings](#strings) 17 | 1. [Functions](#functions) 18 | 1. [Arrow Functions](#arrow-functions) 19 | 1. [Constructors](#constructors) 20 | 1. [Modules](#modules) 21 | 1. [Iterators and Generators](#iterators-and-generators) 22 | 1. [Properties](#properties) 23 | 1. [Variables](#variables) 24 | 1. [Hoisting](#hoisting) 25 | 1. [Comparison Operators & Equality](#comparison-operators--equality) 26 | 1. [Blocks](#blocks) 27 | 1. [Comments](#comments) 28 | 1. [Whitespace](#whitespace) 29 | 1. [Commas](#commas) 30 | 1. [Semicolons](#semicolons) 31 | 1. [Type Casting & Coercion](#type-casting--coercion) 32 | 1. [Naming Conventions](#naming-conventions) 33 | 1. [Accessors](#accessors) 34 | 1. [Events](#events) 35 | 1. [jQuery](#jquery) 36 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility) 37 | 1. [ECMAScript 6 Styles](#ecmascript-6-styles) 38 | 1. [Testing](#testing) 39 | 1. [Performance](#performance) 40 | 1. [Resources](#resources) 41 | 1. [In the Wild](#in-the-wild) 42 | 1. [Translation](#translation) 43 | 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide) 44 | 1. [Chat With Us About Javascript](#chat-with-us-about-javascript) 45 | 1. [Contributors](#contributors) 46 | 1. [License](#license) 47 | 48 | ## Types 49 | 50 | - [1.1](#1.1) **Primitives**: When you access a primitive type you work directly on its value. 51 | 52 | + `string` 53 | + `number` 54 | + `boolean` 55 | + `null` 56 | + `undefined` 57 | 58 | ```javascript 59 | const foo = 1 60 | let bar = foo 61 | 62 | bar = 9 63 | 64 | console.log(foo, bar) // => 1, 9 65 | ``` 66 | - [1.2](#1.2) **Complex**: When you access a complex type you work on a reference to its value. 67 | 68 | + `object` 69 | + `array` 70 | + `function` 71 | 72 | ```javascript 73 | const foo = [1, 2] 74 | const bar = foo 75 | 76 | bar[0] = 9 77 | 78 | console.log(foo[0], bar[0]) // => 9, 9 79 | ``` 80 | 81 | **[⬆ back to top](#table-of-contents)** 82 | 83 | ## References 84 | 85 | - [2.1](#2.1) Use `const` for all of your references; avoid using `var`. 86 | 87 | > Why? This ensures that you can't reassign your references (mutation), which can lead to bugs and difficult to comprehend code. 88 | 89 | ```javascript 90 | // bad 91 | var a = 1 92 | var b = 2 93 | 94 | // good 95 | const a = 1 96 | const b = 2 97 | ``` 98 | 99 | - [2.2](#2.2) If you must mutate references, use `let` instead of `var`. 100 | 101 | > Why? `let` is block-scoped rather than function-scoped like `var`. 102 | 103 | ```javascript 104 | // bad 105 | var count = 1 106 | if (true) { 107 | count += 1 108 | } 109 | 110 | // good, use the let. 111 | let count = 1 112 | if (true) { 113 | count += 1 114 | } 115 | ``` 116 | 117 | - [2.3](#2.3) Note that both `let` and `const` are block-scoped. 118 | 119 | ```javascript 120 | // const and let only exist in the blocks they are defined in. 121 | { 122 | let a = 1 123 | const b = 1 124 | } 125 | console.log(a) // ReferenceError 126 | console.log(b) // ReferenceError 127 | ``` 128 | 129 | **[⬆ back to top](#table-of-contents)** 130 | 131 | ## Objects 132 | 133 | - [3.1](#3.1) Use the literal syntax for object creation. 134 | 135 | ```javascript 136 | // bad 137 | const item = new Object() 138 | 139 | // good 140 | const item = {} 141 | ``` 142 | 143 | - [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. 144 | 145 | ```javascript 146 | // bad 147 | const superman = { 148 | default: { clark: 'kent' }, 149 | private: true, 150 | } 151 | 152 | // good 153 | const superman = { 154 | defaults: { clark: 'kent' }, 155 | hidden: true, 156 | } 157 | ``` 158 | 159 | - [3.3](#3.3) Use readable synonyms in place of reserved words. 160 | 161 | ```javascript 162 | // bad 163 | const superman = { 164 | class: 'alien', 165 | } 166 | 167 | // bad 168 | const superman = { 169 | klass: 'alien', 170 | } 171 | 172 | // good 173 | const superman = { 174 | type: 'alien', 175 | } 176 | ``` 177 | 178 | 179 | - [3.4](#3.4) Use computed property names when creating objects with dynamic property names. 180 | 181 | > Why? They allow you to define all the properties of an object in one place. 182 | 183 | ```javascript 184 | 185 | function getKey(k) { 186 | return `a key named ${k}` 187 | } 188 | 189 | // bad 190 | const obj = { 191 | id: 5, 192 | name: 'San Francisco', 193 | } 194 | obj[getKey('enabled')] = true 195 | 196 | // good 197 | const obj = { 198 | id: 5, 199 | name: 'San Francisco', 200 | [getKey('enabled')]: true, 201 | } 202 | ``` 203 | 204 | 205 | - [3.5](#3.5) Use object method shorthand. 206 | 207 | ```javascript 208 | // bad 209 | const atom = { 210 | value: 1, 211 | 212 | addValue: function (value) { 213 | return atom.value + value 214 | }, 215 | } 216 | 217 | // good 218 | const atom = { 219 | value: 1, 220 | 221 | addValue(value) { 222 | return atom.value + value 223 | }, 224 | } 225 | ``` 226 | 227 | 228 | - [3.6](#3.6) Use property value shorthand. 229 | 230 | > Why? It is shorter to write and descriptive. 231 | 232 | ```javascript 233 | const lukeSkywalker = 'Luke Skywalker' 234 | 235 | // bad 236 | const obj = { 237 | lukeSkywalker: lukeSkywalker, 238 | } 239 | 240 | // good 241 | const obj = { 242 | lukeSkywalker, 243 | } 244 | ``` 245 | 246 | - [3.7](#3.7) Group your shorthand properties at the beginning of your object declaration. 247 | 248 | > Why? It's easier to tell which properties are using the shorthand. 249 | 250 | ```javascript 251 | const anakinSkywalker = 'Anakin Skywalker' 252 | const lukeSkywalker = 'Luke Skywalker' 253 | 254 | // bad 255 | const obj = { 256 | episodeOne: 1, 257 | twoJediWalkIntoACantina: 2, 258 | lukeSkywalker, 259 | episodeThree: 3, 260 | mayTheFourth: 4, 261 | anakinSkywalker, 262 | } 263 | 264 | // good 265 | const obj = { 266 | lukeSkywalker, 267 | anakinSkywalker, 268 | episodeOne: 1, 269 | twoJediWalkIntoACantina: 2, 270 | episodeThree: 3, 271 | mayTheFourth: 4, 272 | } 273 | ``` 274 | 275 | **[⬆ back to top](#table-of-contents)** 276 | 277 | ## Arrays 278 | 279 | - [4.1](#4.1) Use the literal syntax for array creation. 280 | 281 | ```javascript 282 | // bad 283 | const items = new Array() 284 | 285 | // good 286 | const items = [] 287 | ``` 288 | 289 | - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array. 290 | 291 | ```javascript 292 | const someStack = [] 293 | 294 | // bad 295 | someStack[someStack.length] = 'abracadabra' 296 | 297 | // good 298 | someStack.push('abracadabra') 299 | ``` 300 | 301 | 302 | - [4.3](#4.3) Use array spreads `...` to copy arrays. 303 | 304 | ```javascript 305 | // bad 306 | const len = items.length 307 | const itemsCopy = [] 308 | let i 309 | 310 | for (i = 0; i < len; i++) { 311 | itemsCopy[i] = items[i] 312 | } 313 | 314 | // good 315 | const itemsCopy = [...items] 316 | ``` 317 | - [4.4](#4.4) To convert an array-like object to an array, use Array#from. 318 | 319 | ```javascript 320 | const foo = document.querySelectorAll('.foo') 321 | const nodes = Array.from(foo) 322 | ``` 323 | 324 | **[⬆ back to top](#table-of-contents)** 325 | 326 | ## Destructuring 327 | 328 | - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object. 329 | 330 | > Why? Destructuring saves you from creating temporary references for those properties. 331 | 332 | ```javascript 333 | // bad 334 | function getFullName(user) { 335 | const firstName = user.firstName 336 | const lastName = user.lastName 337 | 338 | return `${firstName} ${lastName}` 339 | } 340 | 341 | // good 342 | function getFullName(obj) { 343 | const { firstName, lastName } = obj 344 | return `${firstName} ${lastName}` 345 | } 346 | 347 | // best 348 | function getFullName({ firstName, lastName }) { 349 | return `${firstName} ${lastName}` 350 | } 351 | ``` 352 | 353 | - [5.2](#5.2) Use array destructuring. 354 | 355 | ```javascript 356 | const arr = [1, 2, 3, 4] 357 | 358 | // bad 359 | const first = arr[0] 360 | const second = arr[1] 361 | 362 | // good 363 | const [first, second] = arr 364 | ``` 365 | 366 | - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring. 367 | 368 | > Why? You can add new properties over time or change the order of things without breaking call sites. 369 | 370 | ```javascript 371 | // bad 372 | function processInput(input) { 373 | // then a miracle occurs 374 | return [left, right, top, bottom] 375 | } 376 | 377 | // the caller needs to think about the order of return data 378 | const [left, __, top] = processInput(input) 379 | 380 | // good 381 | function processInput(input) { 382 | // then a miracle occurs 383 | return { left, right, top, bottom } 384 | } 385 | 386 | // the caller selects only the data they need 387 | const { left, right } = processInput(input) 388 | ``` 389 | 390 | 391 | **[⬆ back to top](#table-of-contents)** 392 | 393 | ## Strings 394 | 395 | - [6.1](#6.1) Use single quotes `''` for strings. 396 | 397 | ```javascript 398 | // bad 399 | const name = "Capt. Janeway" 400 | 401 | // good 402 | const name = 'Capt. Janeway' 403 | ``` 404 | 405 | - [6.2](#6.2) Strings longer than 100 characters should be written across multiple lines using string concatenation. 406 | - [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). 407 | 408 | ```javascript 409 | // bad 410 | 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.' 411 | 412 | // bad 413 | const errorMessage = 'This is a super long error that was thrown because \ 414 | of Batman. When you stop to think about how Batman had anything to do \ 415 | with this, you would get nowhere \ 416 | fast.' 417 | 418 | // good 419 | const errorMessage = 'This is a super long error that was thrown because ' + 420 | 'of Batman. When you stop to think about how Batman had anything to do ' + 421 | 'with this, you would get nowhere fast.' 422 | ``` 423 | 424 | 425 | - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation. 426 | 427 | > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features. 428 | 429 | ```javascript 430 | // bad 431 | function sayHi(name) { 432 | return 'How are you, ' + name + '?' 433 | } 434 | 435 | // bad 436 | function sayHi(name) { 437 | return ['How are you, ', name, '?'].join() 438 | } 439 | 440 | // good 441 | function sayHi(name) { 442 | return `How are you, ${name}?` 443 | } 444 | ``` 445 | - [6.5](#6.5) Never use eval() on a string, it opens too many vulnerabilities. 446 | 447 | **[⬆ back to top](#table-of-contents)** 448 | 449 | 450 | ## Functions 451 | 452 | - [7.1](#7.1) Use function declarations instead of function expressions. 453 | 454 | > 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. 455 | 456 | ```javascript 457 | // bad 458 | const foo = function () { 459 | } 460 | 461 | // good 462 | function foo() { 463 | } 464 | ``` 465 | 466 | - [7.2](#7.2) Function expressions: 467 | 468 | ```javascript 469 | // immediately-invoked function expression (IIFE) 470 | (() => { 471 | console.log('Welcome to the Internet. Please follow me.') 472 | })() 473 | ``` 474 | 475 | - [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. 476 | - [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). 477 | 478 | ```javascript 479 | // bad 480 | if (currentUser) { 481 | function test() { 482 | console.log('Nope.') 483 | } 484 | } 485 | 486 | // good 487 | let test 488 | if (currentUser) { 489 | test = () => { 490 | console.log('Yup.') 491 | } 492 | } 493 | ``` 494 | 495 | - [7.5](#7.5) Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope. 496 | 497 | ```javascript 498 | // bad 499 | function nope(name, options, arguments) { 500 | // ...stuff... 501 | } 502 | 503 | // good 504 | function yup(name, options, args) { 505 | // ...stuff... 506 | } 507 | ``` 508 | 509 | 510 | - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead. 511 | 512 | > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`. 513 | 514 | ```javascript 515 | // bad 516 | function concatenateAll() { 517 | const args = Array.prototype.slice.call(arguments) 518 | return args.join('') 519 | } 520 | 521 | // good 522 | function concatenateAll(...args) { 523 | return args.join('') 524 | } 525 | ``` 526 | 527 | 528 | - [7.7](#7.7) Use default parameter syntax rather than mutating function arguments. 529 | 530 | ```javascript 531 | // really bad 532 | function handleThings(opts) { 533 | // No! We shouldn't mutate function arguments. 534 | // Double bad: if opts is falsy it'll be set to an object which may 535 | // be what you want but it can introduce subtle bugs. 536 | opts = opts || {} 537 | // ... 538 | } 539 | 540 | // still bad 541 | function handleThings(opts) { 542 | if (opts === void 0) { 543 | opts = {} 544 | } 545 | // ... 546 | } 547 | 548 | // good 549 | function handleThings(opts = {}) { 550 | // ... 551 | } 552 | ``` 553 | 554 | - [7.8](#7.8) Avoid side effects with default parameters 555 | 556 | > Why? They are confusing to reason about. 557 | 558 | ```javascript 559 | var b = 1 560 | // bad 561 | function count(a = b++) { 562 | console.log(a) 563 | } 564 | count() // 1 565 | count() // 2 566 | count(3) // 3 567 | count() // 3 568 | ``` 569 | 570 | - [7.9](#7.9) Never use the Function constructor to create a new function. 571 | 572 | > Why? Creating a function in this way evaluates a string similarly to eval(), which opens vulnerabilities. 573 | 574 | ```javascript 575 | // bad 576 | var add = new Function('a', 'b', 'return a + b') 577 | 578 | // still bad 579 | var subtract = Function('a', 'b', 'return a - b') 580 | ``` 581 | 582 | **[⬆ back to top](#table-of-contents)** 583 | 584 | ## Arrow Functions 585 | 586 | - [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation. 587 | 588 | > 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. 589 | 590 | > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration. 591 | 592 | ```javascript 593 | // bad 594 | ;[1, 2, 3].map(function (x) { 595 | return x * x 596 | }) 597 | 598 | // good 599 | ;[1, 2, 3].map((x) => { 600 | return x * x 601 | }) 602 | ``` 603 | 604 | - [8.2](#8.2) If the function body fits on one line and there is only a single argument, feel free to omit the braces and parentheses, and use the implicit return. Otherwise, add the parentheses, braces, and use a `return` statement. 605 | 606 | > Why? Syntactic sugar. It reads well when multiple functions are chained together. 607 | 608 | > Why not? If you plan on returning an object. 609 | 610 | ```javascript 611 | // good 612 | ;[1, 2, 3].map(x => x * x) 613 | 614 | // good 615 | ;[1, 2, 3].reduce((total, n) => { 616 | return total + n 617 | }, 0) 618 | ``` 619 | 620 | **[⬆ back to top](#table-of-contents)** 621 | 622 | 623 | ## Constructors 624 | 625 | - [9.1](#9.1) Always use `class`. Avoid manipulating `prototype` directly. 626 | 627 | > Why? `class` syntax is more concise and easier to reason about. 628 | 629 | ```javascript 630 | // bad 631 | function Queue(contents = []) { 632 | this._queue = [...contents] 633 | } 634 | Queue.prototype.pop = function() { 635 | const value = this._queue[0] 636 | this._queue.splice(0, 1) 637 | return value 638 | } 639 | 640 | 641 | // good 642 | class Queue { 643 | constructor(contents = []) { 644 | this._queue = [...contents] 645 | } 646 | pop() { 647 | const value = this._queue[0] 648 | this._queue.splice(0, 1) 649 | return value 650 | } 651 | } 652 | ``` 653 | 654 | - [9.2](#9.2) Use `extends` for inheritance. 655 | 656 | > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`. 657 | 658 | ```javascript 659 | // bad 660 | const inherits = require('inherits') 661 | function PeekableQueue(contents) { 662 | Queue.apply(this, contents) 663 | } 664 | inherits(PeekableQueue, Queue) 665 | PeekableQueue.prototype.peek = function() { 666 | return this._queue[0] 667 | } 668 | 669 | // good 670 | class PeekableQueue extends Queue { 671 | peek() { 672 | return this._queue[0] 673 | } 674 | } 675 | ``` 676 | 677 | - [9.3](#9.3) Methods can return `this` to help with method chaining. 678 | 679 | ```javascript 680 | // bad 681 | Jedi.prototype.jump = function() { 682 | this.jumping = true 683 | return true 684 | } 685 | 686 | Jedi.prototype.setHeight = function(height) { 687 | this.height = height 688 | } 689 | 690 | const luke = new Jedi() 691 | luke.jump() // => true 692 | luke.setHeight(20) // => undefined 693 | 694 | // good 695 | class Jedi { 696 | jump() { 697 | this.jumping = true 698 | return this 699 | } 700 | 701 | setHeight(height) { 702 | this.height = height 703 | return this 704 | } 705 | } 706 | 707 | const luke = new Jedi() 708 | 709 | luke.jump() 710 | .setHeight(20) 711 | ``` 712 | 713 | 714 | - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. 715 | 716 | ```javascript 717 | class Jedi { 718 | constructor(options = {}) { 719 | this.name = options.name || 'no name' 720 | } 721 | 722 | getName() { 723 | return this.name 724 | } 725 | 726 | toString() { 727 | return `Jedi - ${this.getName()}` 728 | } 729 | } 730 | ``` 731 | 732 | **[⬆ back to top](#table-of-contents)** 733 | 734 | 735 | ## Modules 736 | 737 | - [10.1](#10.1) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system. 738 | 739 | > Why? Modules are the future, let's start using the future now. 740 | 741 | ```javascript 742 | // bad 743 | const AirbnbStyleGuide = require('./AirbnbStyleGuide') 744 | module.exports = AirbnbStyleGuide.es6 745 | 746 | // ok 747 | import AirbnbStyleGuide from './AirbnbStyleGuide' 748 | export default AirbnbStyleGuide.es6 749 | 750 | // best 751 | import { es6 } from './AirbnbStyleGuide' 752 | export default es6 753 | ``` 754 | 755 | - [10.2](#10.2) Do not use wildcard imports. 756 | 757 | > Why? This makes sure you have a single default export. 758 | 759 | ```javascript 760 | // bad 761 | import * as AirbnbStyleGuide from './AirbnbStyleGuide' 762 | 763 | // good 764 | import AirbnbStyleGuide from './AirbnbStyleGuide' 765 | ``` 766 | 767 | - [10.3](#10.3) And do not export directly from an import. 768 | 769 | > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent. 770 | 771 | ```javascript 772 | // bad 773 | // filename es6.js 774 | export { es6 as default } from './airbnbStyleGuide' 775 | 776 | // good 777 | // filename es6.js 778 | import { es6 } from './AirbnbStyleGuide' 779 | export default es6 780 | ``` 781 | 782 | **[⬆ back to top](#table-of-contents)** 783 | 784 | ## Iterators and Generators 785 | 786 | - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`. 787 | 788 | > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects. 789 | 790 | ```javascript 791 | const numbers = [1, 2, 3, 4, 5] 792 | 793 | // bad 794 | let sum = 0 795 | for (let num of numbers) { 796 | sum += num 797 | } 798 | 799 | sum === 15 800 | 801 | // good 802 | let sum = 0 803 | numbers.forEach((num) => sum += num) 804 | sum === 15 805 | 806 | // best (use the functional force) 807 | const sum = numbers.reduce((total, num) => total + num, 0) 808 | sum === 15 809 | ``` 810 | 811 | - [11.2](#11.2) Don't use generators for now. 812 | 813 | > Why? They don't transpile well to ES5. 814 | 815 | **[⬆ back to top](#table-of-contents)** 816 | 817 | 818 | ## Properties 819 | 820 | - [12.1](#12.1) Use dot notation when accessing properties. 821 | 822 | ```javascript 823 | const luke = { 824 | jedi: true, 825 | age: 28, 826 | } 827 | 828 | // bad 829 | const isJedi = luke['jedi'] 830 | 831 | // good 832 | const isJedi = luke.jedi 833 | ``` 834 | 835 | - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable. 836 | 837 | ```javascript 838 | const luke = { 839 | jedi: true, 840 | age: 28, 841 | } 842 | 843 | function getProp(prop) { 844 | return luke[prop] 845 | } 846 | 847 | const isJedi = getProp('jedi') 848 | ``` 849 | 850 | **[⬆ back to top](#table-of-contents)** 851 | 852 | 853 | ## Variables 854 | 855 | - [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. 856 | 857 | ```javascript 858 | // bad 859 | superPower = new SuperPower() 860 | 861 | // good 862 | const superPower = new SuperPower() 863 | ``` 864 | 865 | - [13.2](#13.2) Use one `const` declaration per variable. 866 | 867 | > 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. 868 | 869 | ```javascript 870 | // bad 871 | const items = getItems(), 872 | goSportsTeam = true, 873 | dragonball = 'z' 874 | 875 | // bad 876 | // (compare to above, and try to spot the mistake) 877 | const items = getItems(), 878 | goSportsTeam = true 879 | dragonball = 'z' 880 | 881 | // good 882 | const items = getItems() 883 | const goSportsTeam = true 884 | const dragonball = 'z' 885 | ``` 886 | 887 | - [13.3](#13.3) Group all your `const`s and then group all your `let`s. 888 | 889 | > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables. 890 | 891 | ```javascript 892 | // bad 893 | let i, len, dragonball, 894 | items = getItems(), 895 | goSportsTeam = true 896 | 897 | // bad 898 | let i 899 | const items = getItems() 900 | let dragonball 901 | const goSportsTeam = true 902 | let len 903 | 904 | // good 905 | const goSportsTeam = true 906 | const items = getItems() 907 | let dragonball 908 | let i 909 | let length 910 | ``` 911 | 912 | - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place. 913 | 914 | > Why? `let` and `const` are block scoped and not function scoped. 915 | 916 | ```javascript 917 | // good 918 | function() { 919 | test() 920 | console.log('doing stuff..') 921 | 922 | //..other stuff.. 923 | 924 | const name = getName() 925 | 926 | if (name === 'test') { 927 | return false 928 | } 929 | 930 | return name 931 | } 932 | 933 | // bad - unnecessary function call 934 | function(hasName) { 935 | const name = getName() 936 | 937 | if (!hasName) { 938 | return false 939 | } 940 | 941 | this.setFirstName(name) 942 | 943 | return true 944 | } 945 | 946 | // good 947 | function(hasName) { 948 | if (!hasName) { 949 | return false 950 | } 951 | 952 | const name = getName() 953 | this.setFirstName(name) 954 | 955 | return true 956 | } 957 | ``` 958 | 959 | **[⬆ back to top](#table-of-contents)** 960 | 961 | 962 | ## Hoisting 963 | 964 | - [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). 965 | 966 | ```javascript 967 | // we know this wouldn't work (assuming there 968 | // is no notDefined global variable) 969 | function example() { 970 | console.log(notDefined) // => throws a ReferenceError 971 | } 972 | 973 | // creating a variable declaration after you 974 | // reference the variable will work due to 975 | // variable hoisting. Note: the assignment 976 | // value of `true` is not hoisted. 977 | function example() { 978 | console.log(declaredButNotAssigned) // => undefined 979 | var declaredButNotAssigned = true 980 | } 981 | 982 | // The interpreter is hoisting the variable 983 | // declaration to the top of the scope, 984 | // which means our example could be rewritten as: 985 | function example() { 986 | let declaredButNotAssigned 987 | console.log(declaredButNotAssigned) // => undefined 988 | declaredButNotAssigned = true 989 | } 990 | 991 | // using const and let 992 | function example() { 993 | console.log(declaredButNotAssigned) // => throws a ReferenceError 994 | console.log(typeof declaredButNotAssigned) // => throws a ReferenceError 995 | const declaredButNotAssigned = true 996 | } 997 | ``` 998 | 999 | - [14.2](#14.2) Anonymous function expressions hoist their variable name, but not the function assignment. 1000 | 1001 | ```javascript 1002 | function example() { 1003 | console.log(anonymous) // => undefined 1004 | 1005 | anonymous() // => TypeError anonymous is not a function 1006 | 1007 | var anonymous = function() { 1008 | console.log('anonymous function expression') 1009 | } 1010 | } 1011 | ``` 1012 | 1013 | - [14.3](#14.3) Named function expressions hoist the variable name, not the function name or the function body. 1014 | 1015 | ```javascript 1016 | function example() { 1017 | console.log(named) // => undefined 1018 | 1019 | named() // => TypeError named is not a function 1020 | 1021 | superPower() // => ReferenceError superPower is not defined 1022 | 1023 | var named = function superPower() { 1024 | console.log('Flying') 1025 | } 1026 | } 1027 | 1028 | // the same is true when the function name 1029 | // is the same as the variable name. 1030 | function example() { 1031 | console.log(named) // => undefined 1032 | 1033 | named() // => TypeError named is not a function 1034 | 1035 | var named = function named() { 1036 | console.log('named') 1037 | } 1038 | } 1039 | ``` 1040 | 1041 | - [14.4](#14.4) Function declarations hoist their name and the function body. 1042 | 1043 | ```javascript 1044 | function example() { 1045 | superPower() // => Flying 1046 | 1047 | function superPower() { 1048 | console.log('Flying') 1049 | } 1050 | } 1051 | ``` 1052 | 1053 | - 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/). 1054 | 1055 | **[⬆ back to top](#table-of-contents)** 1056 | 1057 | 1058 | ## Comparison Operators & Equality 1059 | 1060 | - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`. 1061 | - [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: 1062 | 1063 | + **Objects** evaluate to **true** 1064 | + **Undefined** evaluates to **false** 1065 | + **Null** evaluates to **false** 1066 | + **Booleans** evaluate to **the value of the boolean** 1067 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true** 1068 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true** 1069 | 1070 | ```javascript 1071 | if ([0]) { 1072 | // true 1073 | // An array is an object, objects evaluate to true 1074 | } 1075 | ``` 1076 | 1077 | - [15.3](#15.3) Use shortcuts. 1078 | 1079 | ```javascript 1080 | // bad 1081 | if (name !== '') { 1082 | // ...stuff... 1083 | } 1084 | 1085 | // good 1086 | if (name) { 1087 | // ...stuff... 1088 | } 1089 | 1090 | // bad 1091 | if (collection.length > 0) { 1092 | // ...stuff... 1093 | } 1094 | 1095 | // good 1096 | if (collection.length) { 1097 | // ...stuff... 1098 | } 1099 | ``` 1100 | 1101 | - [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. 1102 | 1103 | **[⬆ back to top](#table-of-contents)** 1104 | 1105 | 1106 | ## Blocks 1107 | 1108 | - [16.1](#16.1) Use braces with all multi-line blocks. 1109 | 1110 | ```javascript 1111 | // bad 1112 | if (test) 1113 | return false 1114 | 1115 | // good 1116 | if (test) return false 1117 | 1118 | // good 1119 | if (test) { 1120 | return false 1121 | } 1122 | 1123 | // bad 1124 | function() { return false } 1125 | 1126 | // good 1127 | function() { 1128 | return false 1129 | } 1130 | ``` 1131 | 1132 | - [16.2](#16.2) If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your 1133 | `if` block's closing brace. 1134 | 1135 | ```javascript 1136 | // bad 1137 | if (test) { 1138 | thing1() 1139 | thing2() 1140 | } 1141 | else { 1142 | thing3() 1143 | } 1144 | 1145 | // good 1146 | if (test) { 1147 | thing1() 1148 | thing2() 1149 | } else { 1150 | thing3() 1151 | } 1152 | ``` 1153 | 1154 | 1155 | **[⬆ back to top](#table-of-contents)** 1156 | 1157 | 1158 | ## Comments 1159 | 1160 | - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values. 1161 | 1162 | ```javascript 1163 | // bad 1164 | // make() returns a new element 1165 | // based on the passed in tag name 1166 | // 1167 | // @param {String} tag 1168 | // @return {Element} element 1169 | function make(tag) { 1170 | 1171 | // ...stuff... 1172 | 1173 | return element 1174 | } 1175 | 1176 | // good 1177 | /** 1178 | * make() returns a new element 1179 | * based on the passed in tag name 1180 | * 1181 | * @param {String} tag 1182 | * @return {Element} element 1183 | */ 1184 | function make(tag) { 1185 | 1186 | // ...stuff... 1187 | 1188 | return element 1189 | } 1190 | ``` 1191 | 1192 | - [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. 1193 | 1194 | ```javascript 1195 | // bad 1196 | const active = true // is current tab 1197 | 1198 | // good 1199 | // is current tab 1200 | const active = true 1201 | 1202 | // bad 1203 | function getType() { 1204 | console.log('fetching type...') 1205 | // set the default type to 'no type' 1206 | const type = this._type || 'no type' 1207 | 1208 | return type 1209 | } 1210 | 1211 | // good 1212 | function getType() { 1213 | console.log('fetching type...') 1214 | 1215 | // set the default type to 'no type' 1216 | const type = this._type || 'no type' 1217 | 1218 | return type 1219 | } 1220 | ``` 1221 | 1222 | - [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`. 1223 | 1224 | - [17.4](#17.4) Use `// FIXME:` to annotate problems. 1225 | 1226 | ```javascript 1227 | class Calculator extends Abacus { 1228 | constructor() { 1229 | super() 1230 | 1231 | // FIXME: shouldn't use a global here 1232 | total = 0 1233 | } 1234 | } 1235 | ``` 1236 | 1237 | - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems. 1238 | 1239 | ```javascript 1240 | class Calculator extends Abacus { 1241 | constructor() { 1242 | super() 1243 | 1244 | // TODO: total should be configurable by an options param 1245 | this.total = 0 1246 | } 1247 | } 1248 | ``` 1249 | 1250 | **[⬆ back to top](#table-of-contents)** 1251 | 1252 | 1253 | ## Whitespace 1254 | 1255 | - [18.1](#18.1) Use soft tabs set to 2 spaces. 1256 | 1257 | ```javascript 1258 | // bad 1259 | function() { 1260 | ∙∙∙∙const name 1261 | } 1262 | 1263 | // bad 1264 | function() { 1265 | ∙const name 1266 | } 1267 | 1268 | // good 1269 | function() { 1270 | ∙∙const name 1271 | } 1272 | ``` 1273 | 1274 | - [18.2](#18.2) Place 1 space before the leading brace. 1275 | 1276 | ```javascript 1277 | // bad 1278 | function test(){ 1279 | console.log('test') 1280 | } 1281 | 1282 | // good 1283 | function test() { 1284 | console.log('test') 1285 | } 1286 | 1287 | // bad 1288 | dog.set('attr',{ 1289 | age: '1 year', 1290 | breed: 'Bernese Mountain Dog', 1291 | }) 1292 | 1293 | // good 1294 | dog.set('attr', { 1295 | age: '1 year', 1296 | breed: 'Bernese Mountain Dog', 1297 | }) 1298 | ``` 1299 | 1300 | - [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. 1301 | 1302 | ```javascript 1303 | // bad 1304 | if(isJedi) { 1305 | fight () 1306 | } 1307 | 1308 | // good 1309 | if (isJedi) { 1310 | fight() 1311 | } 1312 | 1313 | // bad 1314 | function fight () { 1315 | console.log ('Swooosh!') 1316 | } 1317 | 1318 | // good 1319 | function fight() { 1320 | console.log('Swooosh!') 1321 | } 1322 | ``` 1323 | 1324 | - [18.4](#18.4) Set off operators with spaces. 1325 | 1326 | ```javascript 1327 | // bad 1328 | const x=y+5 1329 | 1330 | // good 1331 | const x = y + 5 1332 | ``` 1333 | 1334 | - [18.5](#18.5) End files with a single newline character. 1335 | 1336 | ```javascript 1337 | // bad 1338 | (function(global) { 1339 | // ...stuff... 1340 | })(this) 1341 | ``` 1342 | 1343 | ```javascript 1344 | // bad 1345 | (function(global) { 1346 | // ...stuff... 1347 | })(this)↵ 1348 | ↵ 1349 | ``` 1350 | 1351 | ```javascript 1352 | // good 1353 | (function(global) { 1354 | // ...stuff... 1355 | })(this)↵ 1356 | ``` 1357 | 1358 | - [18.5](#18.5) Use indentation when making long method chains. Use a leading dot, which 1359 | emphasizes that the line is a method call, not a new statement. 1360 | 1361 | ```javascript 1362 | // bad 1363 | $('#items').find('.selected').highlight().end().find('.open').updateCount() 1364 | 1365 | // bad 1366 | $('#items'). 1367 | find('.selected'). 1368 | highlight(). 1369 | end(). 1370 | find('.open'). 1371 | updateCount() 1372 | 1373 | // good 1374 | $('#items') 1375 | .find('.selected') 1376 | .highlight() 1377 | .end() 1378 | .find('.open') 1379 | .updateCount() 1380 | 1381 | // bad 1382 | const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true) 1383 | .attr('width', (radius + margin) * 2).append('svg:g') 1384 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 1385 | .call(tron.led) 1386 | 1387 | // good 1388 | const leds = stage.selectAll('.led') 1389 | .data(data) 1390 | .enter().append('svg:svg') 1391 | .classed('led', true) 1392 | .attr('width', (radius + margin) * 2) 1393 | .append('svg:g') 1394 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')') 1395 | .call(tron.led) 1396 | ``` 1397 | 1398 | - [18.6](#18.6) Leave a blank line after blocks and before the next statement. 1399 | 1400 | ```javascript 1401 | // bad 1402 | if (foo) { 1403 | return bar 1404 | } 1405 | return baz 1406 | 1407 | // good 1408 | if (foo) { 1409 | return bar 1410 | } 1411 | 1412 | return baz 1413 | 1414 | // bad 1415 | const obj = { 1416 | foo() { 1417 | }, 1418 | bar() { 1419 | }, 1420 | } 1421 | return obj 1422 | 1423 | // good 1424 | const obj = { 1425 | foo() { 1426 | }, 1427 | 1428 | bar() { 1429 | }, 1430 | } 1431 | 1432 | return obj 1433 | 1434 | // bad 1435 | const arr = [ 1436 | function foo() { 1437 | }, 1438 | function bar() { 1439 | }, 1440 | ] 1441 | return arr 1442 | 1443 | // good 1444 | const arr = [ 1445 | function foo() { 1446 | }, 1447 | 1448 | function bar() { 1449 | }, 1450 | ] 1451 | 1452 | return arr 1453 | ``` 1454 | 1455 | 1456 | **[⬆ back to top](#table-of-contents)** 1457 | 1458 | ## Commas 1459 | 1460 | - [19.1](#19.1) Leading commas: **Nope.** 1461 | 1462 | ```javascript 1463 | // bad 1464 | const story = [ 1465 | once 1466 | , upon 1467 | , aTime 1468 | ] 1469 | 1470 | // good 1471 | const story = [ 1472 | once, 1473 | upon, 1474 | aTime, 1475 | ] 1476 | 1477 | // bad 1478 | const hero = { 1479 | firstName: 'Ada' 1480 | , lastName: 'Lovelace' 1481 | , birthYear: 1815 1482 | , superPower: 'computers' 1483 | } 1484 | 1485 | // good 1486 | const hero = { 1487 | firstName: 'Ada', 1488 | lastName: 'Lovelace', 1489 | birthYear: 1815, 1490 | superPower: 'computers', 1491 | } 1492 | ``` 1493 | 1494 | - [19.2](#19.2) Additional trailing comma: **Yup.** 1495 | 1496 | > 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. 1497 | 1498 | ```javascript 1499 | // bad - git diff without trailing comma 1500 | const hero = { 1501 | firstName: 'Florence', 1502 | - lastName: 'Nightingale' 1503 | + lastName: 'Nightingale', 1504 | + inventorOf: ['coxcomb graph', 'modern nursing'] 1505 | } 1506 | 1507 | // good - git diff with trailing comma 1508 | const hero = { 1509 | firstName: 'Florence', 1510 | lastName: 'Nightingale', 1511 | + inventorOf: ['coxcomb chart', 'modern nursing'], 1512 | } 1513 | 1514 | // bad 1515 | const hero = { 1516 | firstName: 'Dana', 1517 | lastName: 'Scully' 1518 | } 1519 | 1520 | const heroes = [ 1521 | 'Batman', 1522 | 'Superman' 1523 | ] 1524 | 1525 | // good 1526 | const hero = { 1527 | firstName: 'Dana', 1528 | lastName: 'Scully', 1529 | } 1530 | 1531 | const heroes = [ 1532 | 'Batman', 1533 | 'Superman', 1534 | ] 1535 | ``` 1536 | 1537 | **[⬆ back to top](#table-of-contents)** 1538 | 1539 | 1540 | ## Semicolons 1541 | 1542 | Avoid using semicolon. There are only few cases when semicolon is absolutely neccesary. 1543 | 1544 | As once described by Isaac Schlueter, a \n character always ends a statement (just like a semicolon) unless one of the following is true: 1545 | 1546 | 1. The statement has an unclosed paren, array literal, or object literal or ends in some other way that is not a valid way to end a statement. (For instance, ending with . or ,.) 1547 | 1. The line is -- or ++ (in which case it will decrement/increment the next token.) 1548 | 1. It is a for(), while(), do, if(), or else, and there is no { 1549 | 1. The next line starts with [, (, +, *, /, -, ,, ., or some other binary operator that can only be found between two tokens in a single expression. 1550 | 1551 | The forth rule is probably the real gotchas, for those cases, use the below approach: 1552 | 1553 | ```javascript 1554 | foo(); 1555 | [1,2,3].forEach(bar); 1556 | ``` 1557 | 1558 | you could do this: 1559 | 1560 | ```javascript 1561 | foo() 1562 | ;[1,2,3].forEach(bar) 1563 | ``` 1564 | 1565 | The advantage is that the prefixes are easier to notice, once you are accustomed to never seeing lines starting with ( or [ without semis. 1566 | 1567 | Read more [here](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-leaders-regarding). 1568 | 1569 | 1570 | **[⬆ back to top](#table-of-contents)** 1571 | 1572 | 1573 | ## Type Casting & Coercion 1574 | 1575 | - [21.1](#21.1) Perform type coercion at the beginning of the statement. 1576 | - [21.2](#21.2) Strings: 1577 | 1578 | ```javascript 1579 | // => this.reviewScore = 9 1580 | 1581 | // bad 1582 | const totalScore = this.reviewScore + '' 1583 | 1584 | // good 1585 | const totalScore = String(this.reviewScore) 1586 | ``` 1587 | 1588 | - [21.3](#21.3) Use `parseInt` for Numbers and always with a radix for type casting. 1589 | 1590 | ```javascript 1591 | const inputValue = '4' 1592 | 1593 | // bad 1594 | const val = new Number(inputValue) 1595 | 1596 | // bad 1597 | const val = +inputValue 1598 | 1599 | // bad 1600 | const val = inputValue >> 0 1601 | 1602 | // bad 1603 | const val = parseInt(inputValue) 1604 | 1605 | // good 1606 | const val = Number(inputValue) 1607 | 1608 | // good 1609 | const val = parseInt(inputValue, 10) 1610 | ``` 1611 | 1612 | - [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. 1613 | 1614 | ```javascript 1615 | // good 1616 | /** 1617 | * parseInt was the reason my code was slow. 1618 | * Bitshifting the String to coerce it to a 1619 | * Number made it a lot faster. 1620 | */ 1621 | const val = inputValue >> 0 1622 | ``` 1623 | 1624 | - [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: 1625 | 1626 | ```javascript 1627 | 2147483647 >> 0 //=> 2147483647 1628 | 2147483648 >> 0 //=> -2147483648 1629 | 2147483649 >> 0 //=> -2147483647 1630 | ``` 1631 | 1632 | - [21.6](#21.6) Booleans: 1633 | 1634 | ```javascript 1635 | const age = 0 1636 | 1637 | // bad 1638 | const hasAge = new Boolean(age) 1639 | 1640 | // good 1641 | const hasAge = Boolean(age) 1642 | 1643 | // good 1644 | const hasAge = !!age 1645 | ``` 1646 | 1647 | **[⬆ back to top](#table-of-contents)** 1648 | 1649 | 1650 | ## Naming Conventions 1651 | 1652 | - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming. 1653 | 1654 | ```javascript 1655 | // bad 1656 | function q() { 1657 | // ...stuff... 1658 | } 1659 | 1660 | // good 1661 | function query() { 1662 | // ..stuff.. 1663 | } 1664 | ``` 1665 | 1666 | - [22.2](#22.2) Use camelCase when naming objects, functions, and instances. 1667 | 1668 | ```javascript 1669 | // bad 1670 | const OBJEcttsssss = {} 1671 | const this_is_my_object = {} 1672 | function c() {} 1673 | 1674 | // good 1675 | const thisIsMyObject = {} 1676 | function thisIsMyFunction() {} 1677 | ``` 1678 | 1679 | - [22.3](#22.3) Use PascalCase when naming constructors or classes. 1680 | 1681 | ```javascript 1682 | // bad 1683 | function user(options) { 1684 | this.name = options.name 1685 | } 1686 | 1687 | const bad = new user({ 1688 | name: 'nope', 1689 | }) 1690 | 1691 | // good 1692 | class User { 1693 | constructor(options) { 1694 | this.name = options.name 1695 | } 1696 | } 1697 | 1698 | const good = new User({ 1699 | name: 'yup', 1700 | }) 1701 | ``` 1702 | 1703 | - [22.4](#22.4) Use a leading underscore `_` when naming private properties. 1704 | 1705 | ```javascript 1706 | // bad 1707 | this.__firstName__ = 'Panda' 1708 | this.firstName_ = 'Panda' 1709 | 1710 | // good 1711 | this._firstName = 'Panda' 1712 | ``` 1713 | 1714 | - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind. 1715 | 1716 | ```javascript 1717 | // bad 1718 | function foo() { 1719 | const self = this 1720 | return function() { 1721 | console.log(self) 1722 | } 1723 | } 1724 | 1725 | // bad 1726 | function foo() { 1727 | const that = this 1728 | return function() { 1729 | console.log(that) 1730 | } 1731 | } 1732 | 1733 | // good 1734 | function foo() { 1735 | return () => { 1736 | console.log(this) 1737 | } 1738 | } 1739 | ``` 1740 | 1741 | - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class. 1742 | ```javascript 1743 | // file contents 1744 | class CheckBox { 1745 | // ... 1746 | } 1747 | export default CheckBox 1748 | 1749 | // in some other file 1750 | // bad 1751 | import CheckBox from './checkBox' 1752 | 1753 | // bad 1754 | import CheckBox from './check_box' 1755 | 1756 | // good 1757 | import CheckBox from './CheckBox' 1758 | ``` 1759 | 1760 | - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name. 1761 | 1762 | ```javascript 1763 | function makeStyleGuide() { 1764 | } 1765 | 1766 | export default makeStyleGuide 1767 | ``` 1768 | 1769 | - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object. 1770 | 1771 | ```javascript 1772 | const AirbnbStyleGuide = { 1773 | es6: { 1774 | } 1775 | } 1776 | 1777 | export default AirbnbStyleGuide 1778 | ``` 1779 | 1780 | 1781 | **[⬆ back to top](#table-of-contents)** 1782 | 1783 | 1784 | ## Accessors 1785 | 1786 | - [23.1](#23.1) Accessor functions for properties are not required. 1787 | - [23.2](#23.2) If you do make accessor functions use getVal() and setVal('hello'). 1788 | 1789 | ```javascript 1790 | // bad 1791 | dragon.age() 1792 | 1793 | // good 1794 | dragon.getAge() 1795 | 1796 | // bad 1797 | dragon.age(25) 1798 | 1799 | // good 1800 | dragon.setAge(25) 1801 | ``` 1802 | 1803 | - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`. 1804 | 1805 | ```javascript 1806 | // bad 1807 | if (!dragon.age()) { 1808 | return false 1809 | } 1810 | 1811 | // good 1812 | if (!dragon.hasAge()) { 1813 | return false 1814 | } 1815 | ``` 1816 | 1817 | - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent. 1818 | 1819 | ```javascript 1820 | class Jedi { 1821 | constructor(options = {}) { 1822 | const lightsaber = options.lightsaber || 'blue' 1823 | this.set('lightsaber', lightsaber) 1824 | } 1825 | 1826 | set(key, val) { 1827 | this[key] = val 1828 | } 1829 | 1830 | get(key) { 1831 | return this[key] 1832 | } 1833 | } 1834 | ``` 1835 | 1836 | **[⬆ back to top](#table-of-contents)** 1837 | 1838 | 1839 | ## Events 1840 | 1841 | - [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: 1842 | 1843 | ```javascript 1844 | // bad 1845 | $(this).trigger('listingUpdated', listing.id) 1846 | 1847 | ... 1848 | 1849 | $(this).on('listingUpdated', function(e, listingId) { 1850 | // do something with listingId 1851 | }) 1852 | ``` 1853 | 1854 | prefer: 1855 | 1856 | ```javascript 1857 | // good 1858 | $(this).trigger('listingUpdated', { listingId : listing.id }) 1859 | 1860 | ... 1861 | 1862 | $(this).on('listingUpdated', function(e, data) { 1863 | // do something with data.listingId 1864 | }) 1865 | ``` 1866 | 1867 | **[⬆ back to top](#table-of-contents)** 1868 | 1869 | 1870 | ## jQuery 1871 | 1872 | - [25.1](#25.1) Prefix jQuery object variables with a `$`. 1873 | 1874 | ```javascript 1875 | // bad 1876 | const sidebar = $('.sidebar') 1877 | 1878 | // good 1879 | const $sidebar = $('.sidebar') 1880 | ``` 1881 | 1882 | - [25.2](#25.2) Cache jQuery lookups. 1883 | 1884 | ```javascript 1885 | // bad 1886 | function setSidebar() { 1887 | $('.sidebar').hide() 1888 | 1889 | // ...stuff... 1890 | 1891 | $('.sidebar').css({ 1892 | 'background-color': 'pink' 1893 | }) 1894 | } 1895 | 1896 | // good 1897 | function setSidebar() { 1898 | const $sidebar = $('.sidebar') 1899 | $sidebar.hide() 1900 | 1901 | // ...stuff... 1902 | 1903 | $sidebar.css({ 1904 | 'background-color': 'pink' 1905 | }) 1906 | } 1907 | ``` 1908 | 1909 | - [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) 1910 | - [25.4](#25.4) Use `find` with scoped jQuery object queries. 1911 | 1912 | ```javascript 1913 | // bad 1914 | $('ul', '.sidebar').hide() 1915 | 1916 | // bad 1917 | $('.sidebar').find('ul').hide() 1918 | 1919 | // good 1920 | $('.sidebar ul').hide() 1921 | 1922 | // good 1923 | $('.sidebar > ul').hide() 1924 | 1925 | // good 1926 | $sidebar.find('ul').hide() 1927 | ``` 1928 | 1929 | **[⬆ back to top](#table-of-contents)** 1930 | 1931 | 1932 | ## ECMAScript 5 Compatibility 1933 | 1934 | - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/). 1935 | 1936 | **[⬆ back to top](#table-of-contents)** 1937 | 1938 | ## ECMAScript 6 Styles 1939 | 1940 | - [27.1](#27.1) This is a collection of links to the various es6 features. 1941 | 1942 | 1. [Arrow Functions](#arrow-functions) 1943 | 1. [Classes](#constructors) 1944 | 1. [Object Shorthand](#es6-object-shorthand) 1945 | 1. [Object Concise](#es6-object-concise) 1946 | 1. [Object Computed Properties](#es6-computed-properties) 1947 | 1. [Template Strings](#es6-template-literals) 1948 | 1. [Destructuring](#destructuring) 1949 | 1. [Default Parameters](#es6-default-parameters) 1950 | 1. [Rest](#es6-rest) 1951 | 1. [Array Spreads](#es6-array-spreads) 1952 | 1. [Let and Const](#references) 1953 | 1. [Iterators and Generators](#iterators-and-generators) 1954 | 1. [Modules](#modules) 1955 | 1956 | **[⬆ back to top](#table-of-contents)** 1957 | 1958 | ## Testing 1959 | 1960 | - [28.1](#28.1) **Yup.** 1961 | 1962 | ```javascript 1963 | function() { 1964 | return true 1965 | } 1966 | ``` 1967 | 1968 | **[⬆ back to top](#table-of-contents)** 1969 | 1970 | 1971 | ## Performance 1972 | 1973 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) 1974 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) 1975 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) 1976 | - [Bang Function](http://jsperf.com/bang-function) 1977 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13) 1978 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text) 1979 | - [Long String Concatenation](http://jsperf.com/ya-string-concat) 1980 | - Loading... 1981 | 1982 | **[⬆ back to top](#table-of-contents)** 1983 | 1984 | 1985 | ## Resources 1986 | 1987 | **Learning ES6** 1988 | 1989 | - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html) 1990 | - [ExploringJS](http://exploringjs.com/) 1991 | - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/) 1992 | - [Comprehensive Overview of ES6 Features](http://es6-features.org/) 1993 | 1994 | **Read This** 1995 | 1996 | - [Standard ECMA-262](http://www.ecma-international.org/ecma-262/6.0/index.html) 1997 | 1998 | **Tools** 1999 | 2000 | - Code Style Linters 2001 | + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc) 2002 | + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc) 2003 | + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json) 2004 | 2005 | **Other Style Guides** 2006 | 2007 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) 2008 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines) 2009 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/) 2010 | 2011 | **Other Styles** 2012 | 2013 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen 2014 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen 2015 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun 2016 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman 2017 | 2018 | **Further Reading** 2019 | 2020 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll 2021 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer 2022 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz 2023 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban 2024 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock 2025 | 2026 | **Books** 2027 | 2028 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford 2029 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov 2030 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz 2031 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders 2032 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas 2033 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw 2034 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig 2035 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch 2036 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault 2037 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg 2038 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy 2039 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon 2040 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov 2041 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman 2042 | - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke 2043 | - [You Don't Know JS: ES6 & Beyond](http://shop.oreilly.com/product/0636920033769.do) - Kyle Simpson 2044 | 2045 | **Blogs** 2046 | 2047 | - [DailyJS](http://dailyjs.com/) 2048 | - [JavaScript Weekly](http://javascriptweekly.com/) 2049 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/) 2050 | - [Bocoup Weblog](http://weblog.bocoup.com/) 2051 | - [Adequately Good](http://www.adequatelygood.com/) 2052 | - [NCZOnline](http://www.nczonline.net/) 2053 | - [Perfection Kills](http://perfectionkills.com/) 2054 | - [Ben Alman](http://benalman.com/) 2055 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/) 2056 | - [Dustin Diaz](http://dustindiaz.com/) 2057 | - [nettuts](http://net.tutsplus.com/?s=javascript) 2058 | 2059 | **Podcasts** 2060 | 2061 | - [JavaScript Jabber](http://devchat.tv/js-jabber/) 2062 | 2063 | 2064 | **[⬆ back to top](#table-of-contents)** 2065 | 2066 | ## In the Wild 2067 | 2068 | 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. 2069 | 2070 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript) 2071 | - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript) 2072 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) 2073 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript) 2074 | - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript) 2075 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript) 2076 | - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript) 2077 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide) 2078 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript) 2079 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript) 2080 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide) 2081 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) 2082 | - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md) 2083 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide) 2084 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript) 2085 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript) 2086 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) 2087 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript) 2088 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) 2089 | - **Huballin**: [huballin/javascript](https://github.com/huballin/javascript) 2090 | - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide) 2091 | - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript) 2092 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions) 2093 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript) 2094 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript) 2095 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript) 2096 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) 2097 | - **MitocGroup**: [MitocGroup/javascript](https://github.com/MitocGroup/javascript) 2098 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) 2099 | - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript) 2100 | - **Muber**: [muber/javascript](https://github.com/muber/javascript) 2101 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) 2102 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript) 2103 | - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript) 2104 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript) 2105 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript) 2106 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) 2107 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript) 2108 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide) 2109 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide) 2110 | - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide) 2111 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) 2112 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript) 2113 | - **Target**: [target/javascript](https://github.com/target/javascript) 2114 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript) 2115 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript) 2116 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide) 2117 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript) 2118 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) 2119 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript) 2120 | 2121 | **[⬆ back to top](#table-of-contents)** 2122 | 2123 | ## Translation 2124 | 2125 | This style guide is also available in other languages: 2126 | 2127 | - ![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) 2128 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 2129 | - ![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) 2130 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 2131 | - ![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) 2132 | - ![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) 2133 | - ![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) 2134 | - ![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) 2135 | - ![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) 2136 | - ![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) 2137 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 2138 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) 2139 | - ![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) 2140 | - ![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) 2141 | 2142 | ## The JavaScript Style Guide Guide 2143 | 2144 | - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) 2145 | 2146 | ## Chat With Us About JavaScript 2147 | 2148 | - Find us on [gitter](https://gitter.im/airbnb/javascript). 2149 | 2150 | ## Contributors 2151 | 2152 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) 2153 | 2154 | 2155 | ## License 2156 | 2157 | (The MIT License) 2158 | 2159 | Copyright (c) 2014 Airbnb 2160 | 2161 | Permission is hereby granted, free of charge, to any person obtaining 2162 | a copy of this software and associated documentation files (the 2163 | 'Software'), to deal in the Software without restriction, including 2164 | without limitation the rights to use, copy, modify, merge, publish, 2165 | distribute, sublicense, and/or sell copies of the Software, and to 2166 | permit persons to whom the Software is furnished to do so, subject to 2167 | the following conditions: 2168 | 2169 | The above copyright notice and this permission notice shall be 2170 | included in all copies or substantial portions of the Software. 2171 | 2172 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 2173 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2174 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2175 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 2176 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 2177 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 2178 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2179 | 2180 | **[⬆ back to top](#table-of-contents)** 2181 | 2182 | # } 2183 | --------------------------------------------------------------------------------