├── .editorconfig
├── .eslintrc
├── .gitignore
├── JavaScript.md
├── LICENSE
├── README.md
└── React.js.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | indent_size = 2
9 | indent_style = space
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | trim_trailing_whitespace = false
15 |
16 | [*.py]
17 | indent_size = 4
18 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "plugins": [
4 | "react"
5 | ],
6 | "env": {
7 | "browser": true,
8 | "node": true
9 | },
10 | "ecmaFeatures": {
11 | "arrowFunctions": true,
12 | "blockBindings": true,
13 | "classes": true,
14 | "defaultParams": true,
15 | "destructuring": true,
16 | "forOf": true,
17 | "generators": false,
18 | "modules": true,
19 | "objectLiteralComputedProperties": true,
20 | "objectLiteralDuplicateProperties": false,
21 | "objectLiteralShorthandMethods": true,
22 | "objectLiteralShorthandProperties": true,
23 | "spread": true,
24 | "superInFunctions": true,
25 | "templateStrings": true,
26 | "jsx": true
27 | },
28 | "rules": {
29 | /**
30 | * Strict mode
31 | */
32 | // babel inserts "use strict"; for us
33 | // http://eslint.org/docs/rules/strict
34 | "strict": [2, "never"],
35 |
36 | /**
37 | * ES6
38 | */
39 | "no-var": 2, // http://eslint.org/docs/rules/no-var
40 |
41 | /**
42 | * Variables
43 | */
44 | "no-shadow": 2, // http://eslint.org/docs/rules/no-shadow
45 | "no-shadow-restricted-names": 2, // http://eslint.org/docs/rules/no-shadow-restricted-names
46 | "no-unused-vars": [2, { // http://eslint.org/docs/rules/no-unused-vars
47 | "vars": "local",
48 | "args": "after-used"
49 | }],
50 | "no-use-before-define": 2, // http://eslint.org/docs/rules/no-use-before-define
51 |
52 | /**
53 | * Possible errors
54 | */
55 | "comma-dangle": [2, "never"], // http://eslint.org/docs/rules/comma-dangle
56 | "no-cond-assign": [2, "always"], // http://eslint.org/docs/rules/no-cond-assign
57 | "no-console": 1, // http://eslint.org/docs/rules/no-console
58 | "no-debugger": 1, // http://eslint.org/docs/rules/no-debugger
59 | "no-alert": 1, // http://eslint.org/docs/rules/no-alert
60 | "no-constant-condition": 1, // http://eslint.org/docs/rules/no-constant-condition
61 | "no-dupe-keys": 2, // http://eslint.org/docs/rules/no-dupe-keys
62 | "no-duplicate-case": 2, // http://eslint.org/docs/rules/no-duplicate-case
63 | "no-empty": 2, // http://eslint.org/docs/rules/no-empty
64 | "no-ex-assign": 2, // http://eslint.org/docs/rules/no-ex-assign
65 | "no-extra-boolean-cast": 0, // http://eslint.org/docs/rules/no-extra-boolean-cast
66 | "no-extra-semi": 2, // http://eslint.org/docs/rules/no-extra-semi
67 | "no-func-assign": 2, // http://eslint.org/docs/rules/no-func-assign
68 | "no-inner-declarations": 2, // http://eslint.org/docs/rules/no-inner-declarations
69 | "no-invalid-regexp": 2, // http://eslint.org/docs/rules/no-invalid-regexp
70 | "no-irregular-whitespace": 2, // http://eslint.org/docs/rules/no-irregular-whitespace
71 | "no-obj-calls": 2, // http://eslint.org/docs/rules/no-obj-calls
72 | "no-reserved-keys": 2, // http://eslint.org/docs/rules/no-reserved-keys
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/
125 | "brace-style": [2, // http://eslint.org/docs/rules/brace-style
126 | "1tbs", {
127 | "allowSingleLine": true
128 | }],
129 | "quotes": [
130 | 2, "single", "avoid-escape" // http://eslint.org/docs/rules/quotes
131 | ],
132 | "camelcase": [2, { // http://eslint.org/docs/rules/camelcase
133 | "properties": "never"
134 | }],
135 | "comma-spacing": [2, { // http://eslint.org/docs/rules/comma-spacing
136 | "before": false,
137 | "after": true
138 | }],
139 | "comma-style": [2, "last"], // http://eslint.org/docs/rules/comma-style
140 | "eol-last": 2, // http://eslint.org/docs/rules/eol-last
141 | "func-names": 1, // http://eslint.org/docs/rules/func-names
142 | "key-spacing": [2, { // http://eslint.org/docs/rules/key-spacing
143 | "beforeColon": false,
144 | "afterColon": true
145 | }],
146 | "new-cap": [2, { // http://eslint.org/docs/rules/new-cap
147 | "newIsCap": true
148 | }],
149 | "no-multiple-empty-lines": [2, { // http://eslint.org/docs/rules/no-multiple-empty-lines
150 | "max": 2
151 | }],
152 | "no-nested-ternary": 2, // http://eslint.org/docs/rules/no-nested-ternary
153 | "no-new-object": 2, // http://eslint.org/docs/rules/no-new-object
154 | "no-spaced-func": 2, // http://eslint.org/docs/rules/no-spaced-func
155 | "no-trailing-spaces": 2, // http://eslint.org/docs/rules/no-trailing-spaces
156 | "no-wrap-func": 2, // http://eslint.org/docs/rules/no-wrap-func
157 | "no-underscore-dangle": 0, // http://eslint.org/docs/rules/no-underscore-dangle
158 | "one-var": [2, "never"], // http://eslint.org/docs/rules/one-var
159 | "padded-blocks": [2, "never"], // http://eslint.org/docs/rules/padded-blocks
160 | "semi": [2, "always"], // http://eslint.org/docs/rules/semi
161 | "semi-spacing": [2, { // http://eslint.org/docs/rules/semi-spacing
162 | "before": false,
163 | "after": true
164 | }],
165 | "space-after-keywords": 2, // http://eslint.org/docs/rules/space-after-keywords
166 | "space-before-blocks": 2, // http://eslint.org/docs/rules/space-before-blocks
167 | "space-before-function-paren": [2, "never"], // http://eslint.org/docs/rules/space-before-function-paren
168 | "space-infix-ops": 2, // http://eslint.org/docs/rules/space-infix-ops
169 | "space-return-throw-case": 2, // http://eslint.org/docs/rules/space-return-throw-case
170 | "spaced-line-comment": 2, // http://eslint.org/docs/rules/spaced-line-comment
171 |
172 | /**
173 | * JSX style
174 | */
175 | "react/display-name": 0,
176 | "react/jsx-boolean-value": 2,
177 | "react/jsx-quotes": [2, "double"],
178 | "react/jsx-no-undef": 2,
179 | "react/jsx-sort-props": 0,
180 | "react/jsx-sort-prop-types": 0,
181 | "react/jsx-uses-react": 2,
182 | "react/jsx-uses-vars": 2,
183 | "react/no-did-mount-set-state": [2, "allow-in-func"],
184 | "react/no-did-update-set-state": 2,
185 | "react/no-multi-comp": 2,
186 | "react/no-unknown-property": 2,
187 | "react/prop-types": 2,
188 | "react/react-in-jsx-scope": 2,
189 | "react/self-closing-comp": 2,
190 | "react/wrap-multilines": 2,
191 | "react/sort-comp": [2, {
192 | "order": [
193 | "displayName",
194 | "mixins",
195 | "statics",
196 | "propTypes",
197 | "getDefaultProps",
198 | "getInitialState",
199 | "componentWillMount",
200 | "componentDidMount",
201 | "componentWillReceiveProps",
202 | "shouldComponentUpdate",
203 | "componentWillUpdate",
204 | "componentWillUnmount",
205 | "/^on.+$/",
206 | "/^get.+$/",
207 | "/^render.+$/",
208 | "render"
209 | ]
210 | }]
211 | }
212 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
--------------------------------------------------------------------------------
/JavaScript.md:
--------------------------------------------------------------------------------
1 | # JavaScript Style Guide() {
2 |
3 | *更合理的 JavaScript 编写方式。 via [Airbnb](https://github.com/airbnb/javascript)*
4 |
5 | [For the ES5-only guide click here](es5/).
6 |
7 | ## 目录
8 |
9 | 1. [类型](#types)
10 | 1. [引用](#references)
11 | 1. [Objects](#objects)
12 | 1. [Arrays](#arrays)
13 | 1. [Destructuring](#destructuring)
14 | 1. [Strings](#strings)
15 | 1. [Functions](#functions)
16 | 1. [Arrow Functions](#arrow-functions)
17 | 1. [Constructors](#constructors)
18 | 1. [Modules](#modules)
19 | 1. [Iterators and Generators](#iterators-and-generators)
20 | 1. [Properties](#properties)
21 | 1. [Variables](#variables)
22 | 1. [Hoisting](#hoisting)
23 | 1. [Comparison Operators & Equality](#comparison-operators--equality)
24 | 1. [Blocks](#blocks)
25 | 1. [Comments](#comments)
26 | 1. [Whitespace](#whitespace)
27 | 1. [Commas](#commas)
28 | 1. [Semicolons](#semicolons)
29 | 1. [Type Casting & Coercion](#type-casting--coercion)
30 | 1. [Naming Conventions](#naming-conventions)
31 | 1. [Accessors](#accessors)
32 | 1. [Events](#events)
33 | 1. [jQuery](#jquery)
34 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
35 | 1. [ECMAScript 6 Styles](#ecmascript-6-styles)
36 | 1. [Testing](#testing)
37 | 1. [Performance](#performance)
38 | 1. [Resources](#resources)
39 | 1. [In the Wild](#in-the-wild)
40 | 1. [Translation](#translation)
41 | 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide)
42 | 1. [Chat With Us About Javascript](#chat-with-us-about-javascript)
43 | 1. [Contributors](#contributors)
44 | 1. [License](#license)
45 |
46 | ## 类型
47 |
48 | - [1.1](#1.1) **基本类型**:基本类型数据直接存取。
49 |
50 | + `string`
51 | + `number`
52 | + `boolean`
53 | + `null`
54 | + `undefined`
55 |
56 | ```javascript
57 | const foo = 1;
58 | let bar = foo;
59 |
60 | bar = 9;
61 |
62 | console.log(foo, bar); // => 1, 9
63 | ```
64 | - [1.2](#1.2) **复杂类型**:复杂数据类型通过**引用**方式存取。
65 |
66 | + `object`
67 | + `array`
68 | + `function`
69 |
70 | ```javascript
71 | const foo = [1, 2];
72 | const bar = foo;
73 |
74 | bar[0] = 9;
75 |
76 | console.log(foo[0], bar[0]); // => 9, 9
77 | ```
78 |
79 | **[⬆ 返回目录](#table-of-contents)**
80 |
81 |
82 | ## 引用
83 |
84 | - [2.1](#2.1) 对所用引用使用 `const`;避免使用 `var`。
85 |
86 | > 为什么?这能确保无法对引用重新赋值,以避免可能导致的 bug 和难以理解的代码。
87 |
88 | ```javascript
89 | // bad
90 | var a = 1;
91 | var b = 2;
92 |
93 | // good
94 | const a = 1;
95 | const b = 2;
96 | ```
97 |
98 | - [2.2](#2.2) 必须使用可变引用时,使用 `let` 而不是 `var`。
99 |
100 | > 为什么?使用块级作用域(`let`),而不是函数作用域(`var`)。
101 |
102 | ```javascript
103 | // bad
104 | var count = 1;
105 | if (true) {
106 | count += 1;
107 | }
108 |
109 | // good, use the let.
110 | let count = 1;
111 | if (true) {
112 | count += 1;
113 | }
114 | ```
115 |
116 | - [2.3](#2.3) 注意:`let` 和 `const` 都是块级作用域。
117 |
118 | ```javascript
119 | // const 和 let 只存在于它们被定义的区块中
120 | {
121 | let a = 1;
122 | const b = 1;
123 | }
124 |
125 | console.log(a); // ReferenceError
126 | console.log(b); // ReferenceError
127 | ```
128 |
129 | **[⬆ 返回目录](#table-of-contents)**
130 |
131 |
132 | ## Objects
133 |
134 | - [3.1](#3.1) 使用字面量语法创建对象。
135 |
136 | ```javascript
137 | // bad
138 | const item = new Object();
139 |
140 | // good
141 | const item = {};
142 | ```
143 |
144 | - [3.2](#3.2) 如果代码在浏览器中执行,不要使用[保留字](http://es5.github.io/#x7.6.1)作为键值,不然的话在 IE8 中不会执行[更多信息](https://github.com/airbnb/javascript/issues/61)(but who care IE8?)。在 ES6 模块和服务器端代码中使用则没有问题。
145 |
146 | ```javascript
147 | // bad
148 | const superman = {
149 | default: {
150 | clark: 'kent'
151 | },
152 | private: true,
153 | };
154 |
155 | // good
156 | const superman = {
157 | defaults: {
158 | clark: 'kent'
159 | },
160 | hidden: true,
161 | };
162 | ```
163 |
164 | - [3.3](#3.3) 使用可读的同义词替换需要使用的保留字。
165 |
166 | ```javascript
167 | // bad
168 | const superman = {
169 | class: 'alien',
170 | };
171 |
172 | // bad
173 | const superman = {
174 | klass: 'alien',
175 | };
176 |
177 | // good
178 | const superman = {
179 | type: 'alien',
180 | };
181 | ```
182 |
183 |
184 | - [3.4](#3.4) 创建包含动态属性名的对象时,使用经过计算的属性名称。
185 |
186 | > 为什么?这样可以一次定义所有属性。
187 |
188 | ```javascript
189 |
190 | function getKey(k) {
191 | return `a key named ${k}`;
192 | }
193 |
194 | // bad
195 | const obj = {
196 | id: 5,
197 | name: 'San Francisco',
198 | };
199 | obj[getKey('enabled')] = true;
200 |
201 | // good
202 | const obj = {
203 | id: 5,
204 | name: 'San Francisco',
205 | [getKey('enabled')]: true,
206 | };
207 | ```
208 |
209 |
210 | - [3.5](#3.5) 使用对象方法简写语法(省略 `function` 关键字)。
211 |
212 | ```javascript
213 | // bad
214 | const atom = {
215 | value: 1,
216 |
217 | addValue: function (value) {
218 | return atom.value + value;
219 | },
220 | };
221 |
222 | // good
223 | const atom = {
224 | value: 1,
225 |
226 | addValue(value) {
227 | return atom.value + value;
228 | },
229 | };
230 | ```
231 |
232 |
233 | - [3.6](#3.6) 使用属性值简写语法。
234 |
235 | > 为什么?这样更简洁、更具描述性。
236 |
237 | ```javascript
238 | const lukeSkywalker = 'Luke Skywalker';
239 |
240 | // bad
241 | const obj = {
242 | lukeSkywalker: lukeSkywalker,
243 | };
244 |
245 | // good
246 | const obj = {
247 | lukeSkywalker,
248 | };
249 | ```
250 |
251 | - [3.7](#3.7) 把简写的属性分组排列在对象声明顶部。
252 | > 为什么?这样更容易区分哪些属性采用了简写。
253 |
254 | ```javascript
255 | const anakinSkywalker = 'Anakin Skywalker';
256 | const lukeSkywalker = 'Luke Skywalker';
257 |
258 | // bad
259 | const obj = {
260 | episodeOne: 1,
261 | twoJediWalkIntoACantina: 2,
262 | lukeSkywalker,
263 | episodeThree: 3,
264 | mayTheFourth: 4,
265 | anakinSkywalker,
266 | };
267 |
268 | // good
269 | const obj = {
270 | lukeSkywalker,
271 | anakinSkywalker,
272 | episodeOne: 1,
273 | twoJediWalkIntoACantina: 2,
274 | episodeThree: 3,
275 | mayTheFourth: 4,
276 | };
277 | ```
278 |
279 | **[⬆ 返回目录](#table-of-contents)**
280 |
281 |
282 |
283 | ## 数组
284 |
285 | - [4.1](#4.1) 使用字面量语法创建数组。
286 |
287 | ```javascript
288 | // bad
289 | const items = new Array();
290 |
291 | // good
292 | const items = [];
293 | ```
294 |
295 | - [4.2](#4.2) 使用 `push` 添加元素,而不是直接赋值。
296 |
297 | ```javascript
298 | const someStack = [];
299 |
300 |
301 | // bad
302 | someStack[someStack.length] = 'abracadabra';
303 |
304 | // good
305 | someStack.push('abracadabra');
306 | ```
307 |
308 |
309 | - [4.3](#4.3) 使用数组扩展运算符 `...` 拷贝数组。
310 |
311 | ```javascript
312 | // bad
313 | const len = items.length;
314 | const itemsCopy = [];
315 | let i;
316 |
317 | for (i = 0; i < len; i++) {
318 | itemsCopy[i] = items[i];
319 | }
320 |
321 | // good
322 | const itemsCopy = [...items];
323 | ```
324 | - [4.4](#4.4) 使用 `Array.from` 转换类数组对象。
325 |
326 | ```javascript
327 | const foo = document.querySelectorAll('.foo');
328 | const nodes = Array.from(foo);
329 | ```
330 |
331 | **[⬆ 返回目录](#table-of-contents)**
332 |
333 |
334 |
335 | ## 解构
336 |
337 | - [5.1](#5.1) 调用对象的多个属性时,使用解构语法。
338 |
339 | > 为什么?解构可以减少临时引用属性。
340 |
341 | ```javascript
342 | // bad
343 | function getFullName(user) {
344 | const firstName = user.firstName;
345 | const lastName = user.lastName;
346 |
347 | return `${firstName} ${lastName}`;
348 | }
349 |
350 | // good
351 | function getFullName(obj) {
352 | const { firstName, lastName } = obj;
353 | return `${firstName} ${lastName}`;
354 | }
355 |
356 | // best
357 | function getFullName({ firstName, lastName }) {
358 | return `${firstName} ${lastName}`;
359 | }
360 | ```
361 |
362 | - [5.2](#5.2) 使用数组解构。
363 |
364 |
365 | ```javascript
366 | const arr = [1, 2, 3, 4];
367 |
368 | // bad
369 | const first = arr[0];
370 | const second = arr[1];
371 |
372 | // good
373 | const [first, second] = arr;
374 | ```
375 |
376 | - [5.3](#5.3) 多个返回值时使用对象解构,而不是数组。
377 |
378 | > 为什么?对象顺序不敏感,方便添加新属性。
379 |
380 | ```javascript
381 | // bad
382 | function processInput(input) {
383 | // then a miracle occurs
384 | return [left, right, top, bottom];
385 | }
386 |
387 | // the caller needs to think about the order of return data
388 | const [left, __, top] = processInput(input);
389 |
390 | // good
391 | function processInput(input) {
392 | // then a miracle occurs
393 | return { left, right, top, bottom };
394 | }
395 |
396 | // the caller selects only the data they need
397 | const { left, right } = processInput(input);
398 | ```
399 |
400 |
401 | **[⬆ 返回目录](#table-of-contents)**
402 |
403 |
404 | ## 字符串
405 |
406 | - [6.1](#6.1) 使用单引号 `''`。
407 |
408 | ```javascript
409 | // bad
410 | const name = "Capt. Janeway";
411 |
412 | // good
413 | const name = 'Capt. Janeway';
414 | ```
415 |
416 | - [6.2](#6.2) 长度超过 80 个字符的字符串应采用多行拼接。
417 | - [6.3](#6.3) 注意:过度使用长字符串拼接会影响性能。[jsPerf 测试](http://jsperf.com/ya-string-concat) & [讨论](https://github.com/airbnb/javascript/issues/40)。
418 |
419 | ```javascript
420 | // bad
421 | 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.';
422 |
423 | // bad
424 | const errorMessage = 'This is a super long error that was thrown because \
425 | of Batman. When you stop to think about how Batman had anything to do \
426 | with this, you would get nowhere \
427 | fast.';
428 |
429 | // good
430 | const errorMessage = 'This is a super long error that was thrown because ' +
431 | 'of Batman. When you stop to think about how Batman had anything to do ' +
432 | 'with this, you would get nowhere fast.';
433 | ```
434 |
435 |
436 | - [6.4](#6.4) 编程创建字符串时使用模板语法替代拼接。
437 | > 为什么?模板字符串提供换行、变量插入功能,让代码更简洁易读。
438 |
439 | ```javascript
440 | // bad
441 | function sayHi(name) {
442 | return 'How are you, ' + name + '?';
443 | }
444 |
445 | // bad
446 | function sayHi(name) {
447 | return ['How are you, ', name, '?'].join();
448 | }
449 |
450 | // good
451 | function sayHi(name) {
452 | return `How are you, ${name}?`;
453 | }
454 | ```
455 |
456 | **[⬆ 返回目录](#table-of-contents)**
457 |
458 |
459 |
460 | ## Functions
461 |
462 | - [7.1](#7.1) 使用函数声明而不是函数表达式。
463 |
464 | > 为什么?函数声明是命名的,易于跟踪调试;函数声明把真个函数提升,而函数表达式只提升引用的变量名。此规则使得 [箭头函数](#arrow-functions) 可以替代函数表达式。
465 |
466 | ```javascript
467 | // bad
468 | const foo = function () {
469 | };
470 |
471 | // good
472 | function foo() {
473 | }
474 | ```
475 |
476 | - [7.2](#7.2) 函数表达式:
477 |
478 | ```javascript
479 | // immediately-invoked function expression (IIFE)
480 | (() => {
481 | console.log('Welcome to the Internet. Please follow me.');
482 | })();
483 | ```
484 |
485 | - [7.3](#7.3) 绝不要在非函数代码块中声明函数(`if`、`while` 等等),可以把函数赋值给一个变量。浏览器允许这么做,但解析结果会不一致。
486 |
487 | - [7.4](#7.4) **注意:** ECMA-262 为一系列语句定义了「块」(`block`),函数什么并不包含在其中。 [阅读 ECMA-262 关于这个问题问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97).
488 |
489 | ```javascript
490 | // bad
491 | if (currentUser) {
492 | function test() {
493 | console.log('Nope.');
494 | }
495 | }
496 |
497 | // good
498 | let test;
499 | if (currentUser) {
500 | test = () => {
501 | console.log('Yup.');
502 | };
503 | }
504 | ```
505 |
506 | - [7.5](#7.5) 绝不要把参数命名为 `arguments`,这会覆盖每个函数作用域里的 `arguments` 对象。
507 |
508 | ```javascript
509 | // bad
510 | function nope(name, options, arguments) {
511 | // ...stuff...
512 | }
513 |
514 | // good
515 | function yup(name, options, args) {
516 | // ...stuff...
517 | }
518 | ```
519 |
520 |
521 | - [7.6](#7.6) 绝不要使用 `arguments`,使用 `...` 语法代替。
522 |
523 | > 为什么? `...` 明确地反应所处理的参数;`...` 语法返回一个真正的数组,而不是像 `arguments` 一样的类数组。
524 |
525 | ```javascript
526 | // bad
527 | function concatenateAll() {
528 | const args = Array.prototype.slice.call(arguments);
529 | return args.join('');
530 | }
531 |
532 | // good
533 | function concatenateAll(...args) {
534 | return args.join('');
535 | }
536 | ```
537 |
538 |
539 | - [7.7](#7.7) 使用默认参数语法,而不是去改变函数参数。
540 |
541 | ```javascript
542 | // really bad
543 | function handleThings(opts) {
544 | // No! We shouldn't mutate function arguments.
545 | // Double bad: if opts is falsy it'll be set to an object which may
546 | // be what you want but it can introduce subtle bugs.
547 | opts = opts || {};
548 | // ...
549 | }
550 |
551 | // still bad
552 | function handleThings(opts) {
553 | if (opts === void 0) {
554 | opts = {};
555 | }
556 | // ...
557 | }
558 |
559 | // good
560 | function handleThings(opts = {}) {
561 | // ...
562 | }
563 | ```
564 |
565 | - [7.8](#7.8) 设置默认参数时应避免产生其他影响。
566 |
567 | > 为什么?这会产生令人迷惑的结果。
568 |
569 | ```javascript
570 | var b = 1;
571 | // bad
572 | function count(a = b++) {
573 | console.log(a);
574 | }
575 | count(); // 1
576 | count(); // 2
577 | count(3); // 3
578 | count(); // 3
579 | ```
580 |
581 |
582 | **[⬆ 返回目录](#table-of-contents)**
583 |
584 |
585 | ## 箭头函数
586 |
587 | - [8.1](#8.1) 必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数语法。
588 | > 为什么?箭头函数自动绑定执行上下文文为创建时的 `this`;更简洁。
589 |
590 | > 为什么不?当遇到复杂的函数时,或许应该把逻辑放到独立的函数声明中去。
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) 函数体只有一行、只有一个参数而且不需要返回值时,可以省略花括号和圆括号。否则,保留括号,并使用 `return` 语句。
605 |
606 | > 为什么?语法糖。多个函数连缀时可读性很好。
607 | > 为什么不?需要返回值的时候。
608 |
609 | ```javascript
610 | // good
611 | [1, 2, 3].map(x => x * x);
612 |
613 | // good
614 | [1, 2, 3].reduce((total, n) => {
615 | return total + n;
616 | }, 0);
617 | ```
618 |
619 | **[⬆ 返回目录](#table-of-contents)**
620 |
621 |
622 | ## Constructors
623 |
624 | - [9.1](#9.1) Always use `class`. Avoid manipulating `prototype` directly.
625 |
626 | > Why? `class` syntax is more concise and easier to reason about.
627 |
628 | ```javascript
629 | // bad
630 | function Queue(contents = []) {
631 | this._queue = [...contents];
632 | }
633 | Queue.prototype.pop = function() {
634 | const value = this._queue[0];
635 | this._queue.splice(0, 1);
636 | return value;
637 | }
638 |
639 |
640 | // good
641 | class Queue {
642 | constructor(contents = []) {
643 | this._queue = [...contents];
644 | }
645 | pop() {
646 | const value = this._queue[0];
647 | this._queue.splice(0, 1);
648 | return value;
649 | }
650 | }
651 | ```
652 |
653 | - [9.2](#9.2) Use `extends` for inheritance.
654 |
655 | > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`.
656 |
657 | ```javascript
658 | // bad
659 | const inherits = require('inherits');
660 | function PeekableQueue(contents) {
661 | Queue.apply(this, contents);
662 | }
663 | inherits(PeekableQueue, Queue);
664 | PeekableQueue.prototype.peek = function() {
665 | return this._queue[0];
666 | }
667 |
668 | // good
669 | class PeekableQueue extends Queue {
670 | peek() {
671 | return this._queue[0];
672 | }
673 | }
674 | ```
675 |
676 | - [9.3](#9.3) Methods can return `this` to help with method chaining.
677 |
678 | ```javascript
679 | // bad
680 | Jedi.prototype.jump = function() {
681 | this.jumping = true;
682 | return true;
683 | };
684 |
685 | Jedi.prototype.setHeight = function(height) {
686 | this.height = height;
687 | };
688 |
689 | const luke = new Jedi();
690 | luke.jump(); // => true
691 | luke.setHeight(20); // => undefined
692 |
693 | // good
694 | class Jedi {
695 | jump() {
696 | this.jumping = true;
697 | return this;
698 | }
699 |
700 | setHeight(height) {
701 | this.height = height;
702 | return this;
703 | }
704 | }
705 |
706 | const luke = new Jedi();
707 |
708 | luke.jump()
709 | .setHeight(20);
710 | ```
711 |
712 |
713 | - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects.
714 |
715 | ```javascript
716 | class Jedi {
717 | constructor(options = {}) {
718 | this.name = options.name || 'no name';
719 | }
720 |
721 | getName() {
722 | return this.name;
723 | }
724 |
725 | toString() {
726 | return `Jedi - ${this.getName()}`;
727 | }
728 | }
729 | ```
730 |
731 | **[⬆ 返回目录](#table-of-contents)**
732 |
733 |
734 | ## Modules
735 |
736 | - [10.1](#10.1) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system.
737 |
738 | > Why? Modules are the future, let's start using the future now.
739 |
740 | ```javascript
741 | // bad
742 | const AirbnbStyleGuide = require('./AirbnbStyleGuide');
743 | module.exports = AirbnbStyleGuide.es6;
744 |
745 | // ok
746 | import AirbnbStyleGuide from './AirbnbStyleGuide';
747 | export default AirbnbStyleGuide.es6;
748 |
749 | // best
750 | import { es6 } from './AirbnbStyleGuide';
751 | export default es6;
752 | ```
753 |
754 | - [10.2](#10.2) Do not use wildcard imports.
755 |
756 | > Why? This makes sure you have a single default export.
757 |
758 | ```javascript
759 | // bad
760 | import * as AirbnbStyleGuide from './AirbnbStyleGuide';
761 |
762 | // good
763 | import AirbnbStyleGuide from './AirbnbStyleGuide';
764 | ```
765 |
766 | - [10.3](#10.3) And do not export directly from an import.
767 |
768 | > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
769 |
770 | ```javascript
771 | // bad
772 | // filename es6.js
773 | export { es6 as default } from './airbnbStyleGuide';
774 |
775 | // good
776 | // filename es6.js
777 | import { es6 } from './AirbnbStyleGuide';
778 | export default es6;
779 | ```
780 |
781 | **[⬆ 返回目录](#table-of-contents)**
782 |
783 | ## Iterators and Generators
784 |
785 | - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`.
786 |
787 | > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects.
788 |
789 | ```javascript
790 | const numbers = [1, 2, 3, 4, 5];
791 |
792 | // bad
793 | let sum = 0;
794 | for (let num of numbers) {
795 | sum += num;
796 | }
797 |
798 | sum === 15;
799 |
800 | // good
801 | let sum = 0;
802 | numbers.forEach((num) => sum += num);
803 | sum === 15;
804 |
805 | // best (use the functional force)
806 | const sum = numbers.reduce((total, num) => total + num, 0);
807 | sum === 15;
808 | ```
809 |
810 | - [11.2](#11.2) Don't use generators for now.
811 |
812 | > Why? They don't transpile well to ES5.
813 |
814 | **[⬆ 返回目录](#table-of-contents)**
815 |
816 |
817 | ## Properties
818 |
819 | - [12.1](#12.1) Use dot notation when accessing properties.
820 |
821 | ```javascript
822 | const luke = {
823 | jedi: true,
824 | age: 28,
825 | };
826 |
827 | // bad
828 | const isJedi = luke['jedi'];
829 |
830 | // good
831 | const isJedi = luke.jedi;
832 | ```
833 |
834 | - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable.
835 |
836 | ```javascript
837 | const luke = {
838 | jedi: true,
839 | age: 28,
840 | };
841 |
842 | function getProp(prop) {
843 | return luke[prop];
844 | }
845 |
846 | const isJedi = getProp('jedi');
847 | ```
848 |
849 | **[⬆ 返回目录](#table-of-contents)**
850 |
851 |
852 | ## Variables
853 |
854 | - [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.
855 |
856 | ```javascript
857 | // bad
858 | superPower = new SuperPower();
859 |
860 | // good
861 | const superPower = new SuperPower();
862 | ```
863 |
864 | - [13.2](#13.2) Use one `const` declaration per variable.
865 |
866 | > 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.
867 |
868 | ```javascript
869 | // bad
870 | const items = getItems(),
871 | goSportsTeam = true,
872 | dragonball = 'z';
873 |
874 | // bad
875 | // (compare to above, and try to spot the mistake)
876 | const items = getItems(),
877 | goSportsTeam = true;
878 | dragonball = 'z';
879 |
880 | // good
881 | const items = getItems();
882 | const goSportsTeam = true;
883 | const dragonball = 'z';
884 | ```
885 |
886 | - [13.3](#13.3) Group all your `const`s and then group all your `let`s.
887 |
888 | > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
889 |
890 | ```javascript
891 | // bad
892 | let i, len, dragonball,
893 | items = getItems(),
894 | goSportsTeam = true;
895 |
896 | // bad
897 | let i;
898 | const items = getItems();
899 | let dragonball;
900 | const goSportsTeam = true;
901 | let len;
902 |
903 | // good
904 | const goSportsTeam = true;
905 | const items = getItems();
906 | let dragonball;
907 | let i;
908 | let length;
909 | ```
910 |
911 | - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place.
912 |
913 | > Why? `let` and `const` are block scoped and not function scoped.
914 |
915 | ```javascript
916 | // good
917 | function() {
918 | test();
919 | console.log('doing stuff..');
920 |
921 | //..other stuff..
922 |
923 | const name = getName();
924 |
925 | if (name === 'test') {
926 | return false;
927 | }
928 |
929 | return name;
930 | }
931 |
932 | // bad - unnecessary function call
933 | function(hasName) {
934 | const name = getName();
935 |
936 | if (!hasName) {
937 | return false;
938 | }
939 |
940 | this.setFirstName(name);
941 |
942 | return true;
943 | }
944 |
945 | // good
946 | function(hasName) {
947 | if (!hasName) {
948 | return false;
949 | }
950 |
951 | const name = getName();
952 | this.setFirstName(name);
953 |
954 | return true;
955 | }
956 | ```
957 |
958 | **[⬆ 返回目录](#table-of-contents)**
959 |
960 |
961 | ## Hoisting
962 |
963 | - [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).
964 |
965 | ```javascript
966 | // we know this wouldn't work (assuming there
967 | // is no notDefined global variable)
968 | function example() {
969 | console.log(notDefined); // => throws a ReferenceError
970 | }
971 |
972 | // creating a variable declaration after you
973 | // reference the variable will work due to
974 | // variable hoisting. Note: the assignment
975 | // value of `true` is not hoisted.
976 | function example() {
977 | console.log(declaredButNotAssigned); // => undefined
978 | var declaredButNotAssigned = true;
979 | }
980 |
981 | // The interpreter is hoisting the variable
982 | // declaration to the top of the scope,
983 | // which means our example could be rewritten as:
984 | function example() {
985 | let declaredButNotAssigned;
986 | console.log(declaredButNotAssigned); // => undefined
987 | declaredButNotAssigned = true;
988 | }
989 |
990 | // using const and let
991 | function example() {
992 | console.log(declaredButNotAssigned); // => throws a ReferenceError
993 | console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
994 | const declaredButNotAssigned = true;
995 | }
996 | ```
997 |
998 | - [14.2](#14.2) Anonymous function expressions hoist their variable name, but not the function assignment.
999 |
1000 | ```javascript
1001 | function example() {
1002 | console.log(anonymous); // => undefined
1003 |
1004 | anonymous(); // => TypeError anonymous is not a function
1005 |
1006 | var anonymous = function() {
1007 | console.log('anonymous function expression');
1008 | };
1009 | }
1010 | ```
1011 |
1012 | - [14.3](#14.3) Named function expressions hoist the variable name, not the function name or the function body.
1013 |
1014 | ```javascript
1015 | function example() {
1016 | console.log(named); // => undefined
1017 |
1018 | named(); // => TypeError named is not a function
1019 |
1020 | superPower(); // => ReferenceError superPower is not defined
1021 |
1022 | var named = function superPower() {
1023 | console.log('Flying');
1024 | };
1025 | }
1026 |
1027 | // the same is true when the function name
1028 | // is the same as the variable name.
1029 | function example() {
1030 | console.log(named); // => undefined
1031 |
1032 | named(); // => TypeError named is not a function
1033 |
1034 | var named = function named() {
1035 | console.log('named');
1036 | }
1037 | }
1038 | ```
1039 |
1040 | - [14.4](#14.4) Function declarations hoist their name and the function body.
1041 |
1042 | ```javascript
1043 | function example() {
1044 | superPower(); // => Flying
1045 |
1046 | function superPower() {
1047 | console.log('Flying');
1048 | }
1049 | }
1050 | ```
1051 |
1052 | - 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/).
1053 |
1054 | **[⬆ 返回目录](#table-of-contents)**
1055 |
1056 |
1057 | ## Comparison Operators & Equality
1058 |
1059 | - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`.
1060 | - [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:
1061 |
1062 | + **Objects** evaluate to **true**
1063 | + **Undefined** evaluates to **false**
1064 | + **Null** evaluates to **false**
1065 | + **Booleans** evaluate to **the value of the boolean**
1066 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true**
1067 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true**
1068 |
1069 | ```javascript
1070 | if ([0]) {
1071 | // true
1072 | // An array is an object, objects evaluate to true
1073 | }
1074 | ```
1075 |
1076 | - [15.3](#15.3) Use shortcuts.
1077 |
1078 | ```javascript
1079 | // bad
1080 | if (name !== '') {
1081 | // ...stuff...
1082 | }
1083 |
1084 | // good
1085 | if (name) {
1086 | // ...stuff...
1087 | }
1088 |
1089 | // bad
1090 | if (collection.length > 0) {
1091 | // ...stuff...
1092 | }
1093 |
1094 | // good
1095 | if (collection.length) {
1096 | // ...stuff...
1097 | }
1098 | ```
1099 |
1100 | - [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.
1101 |
1102 | **[⬆ 返回目录](#table-of-contents)**
1103 |
1104 |
1105 | ## Blocks
1106 |
1107 | - [16.1](#16.1) Use braces with all multi-line blocks.
1108 |
1109 | ```javascript
1110 | // bad
1111 | if (test)
1112 | return false;
1113 |
1114 | // good
1115 | if (test) return false;
1116 |
1117 | // good
1118 | if (test) {
1119 | return false;
1120 | }
1121 |
1122 | // bad
1123 | function() { return false; }
1124 |
1125 | // good
1126 | function() {
1127 | return false;
1128 | }
1129 | ```
1130 |
1131 | - [16.2](#16.2) If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your
1132 | `if` block's closing brace.
1133 |
1134 | ```javascript
1135 | // bad
1136 | if (test) {
1137 | thing1();
1138 | thing2();
1139 | }
1140 | else {
1141 | thing3();
1142 | }
1143 |
1144 | // good
1145 | if (test) {
1146 | thing1();
1147 | thing2();
1148 | } else {
1149 | thing3();
1150 | }
1151 | ```
1152 |
1153 |
1154 | **[⬆ 返回目录](#table-of-contents)**
1155 |
1156 |
1157 | ## Comments
1158 |
1159 | - [17.1](#17.1) Use `/** ... */` for multi-line comments. Include a description, specify types and values for all parameters and return values.
1160 |
1161 | ```javascript
1162 | // bad
1163 | // make() returns a new element
1164 | // based on the passed in tag name
1165 | //
1166 | // @param {String} tag
1167 | // @return {Element} element
1168 | function make(tag) {
1169 |
1170 | // ...stuff...
1171 |
1172 | return element;
1173 | }
1174 |
1175 | // good
1176 | /**
1177 | * make() returns a new element
1178 | * based on the passed in tag name
1179 | *
1180 | * @param {String} tag
1181 | * @return {Element} element
1182 | */
1183 | function make(tag) {
1184 |
1185 | // ...stuff...
1186 |
1187 | return element;
1188 | }
1189 | ```
1190 |
1191 | - [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.
1192 |
1193 | ```javascript
1194 | // bad
1195 | const active = true; // is current tab
1196 |
1197 | // good
1198 | // is current tab
1199 | const active = true;
1200 |
1201 | // bad
1202 | function getType() {
1203 | console.log('fetching type...');
1204 | // set the default type to 'no type'
1205 | const type = this._type || 'no type';
1206 |
1207 | return type;
1208 | }
1209 |
1210 | // good
1211 | function getType() {
1212 | console.log('fetching type...');
1213 |
1214 | // set the default type to 'no type'
1215 | const type = this._type || 'no type';
1216 |
1217 | return type;
1218 | }
1219 | ```
1220 |
1221 | - [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`.
1222 |
1223 | - [17.4](#17.4) Use `// FIXME:` to annotate problems.
1224 |
1225 | ```javascript
1226 | class Calculator {
1227 | constructor() {
1228 | // FIXME: shouldn't use a global here
1229 | total = 0;
1230 | }
1231 | }
1232 | ```
1233 |
1234 | - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems.
1235 |
1236 | ```javascript
1237 | class Calculator {
1238 | constructor() {
1239 | // TODO: total should be configurable by an options param
1240 | this.total = 0;
1241 | }
1242 | }
1243 | ```
1244 |
1245 | **[⬆ 返回目录](#table-of-contents)**
1246 |
1247 |
1248 | ## Whitespace
1249 |
1250 | - [18.1](#18.1) Use soft tabs set to 2 spaces.
1251 |
1252 | ```javascript
1253 | // bad
1254 | function() {
1255 | ∙∙∙∙const name;
1256 | }
1257 |
1258 | // bad
1259 | function() {
1260 | ∙const name;
1261 | }
1262 |
1263 | // good
1264 | function() {
1265 | ∙∙const name;
1266 | }
1267 | ```
1268 |
1269 | - [18.2](#18.2) Place 1 space before the leading brace.
1270 |
1271 | ```javascript
1272 | // bad
1273 | function test(){
1274 | console.log('test');
1275 | }
1276 |
1277 | // good
1278 | function test() {
1279 | console.log('test');
1280 | }
1281 |
1282 | // bad
1283 | dog.set('attr',{
1284 | age: '1 year',
1285 | breed: 'Bernese Mountain Dog',
1286 | });
1287 |
1288 | // good
1289 | dog.set('attr', {
1290 | age: '1 year',
1291 | breed: 'Bernese Mountain Dog',
1292 | });
1293 | ```
1294 |
1295 | - [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.
1296 |
1297 | ```javascript
1298 | // bad
1299 | if(isJedi) {
1300 | fight ();
1301 | }
1302 |
1303 | // good
1304 | if (isJedi) {
1305 | fight();
1306 | }
1307 |
1308 | // bad
1309 | function fight () {
1310 | console.log ('Swooosh!');
1311 | }
1312 |
1313 | // good
1314 | function fight() {
1315 | console.log('Swooosh!');
1316 | }
1317 | ```
1318 |
1319 | - [18.4](#18.4) Set off operators with spaces.
1320 |
1321 | ```javascript
1322 | // bad
1323 | const x=y+5;
1324 |
1325 | // good
1326 | const x = y + 5;
1327 | ```
1328 |
1329 | - [18.5](#18.5) End files with a single newline character.
1330 |
1331 | ```javascript
1332 | // bad
1333 | (function(global) {
1334 | // ...stuff...
1335 | })(this);
1336 | ```
1337 |
1338 | ```javascript
1339 | // bad
1340 | (function(global) {
1341 | // ...stuff...
1342 | })(this);↵
1343 | ↵
1344 | ```
1345 |
1346 | ```javascript
1347 | // good
1348 | (function(global) {
1349 | // ...stuff...
1350 | })(this);↵
1351 | ```
1352 |
1353 | - [18.5](#18.5) Use indentation when making long method chains. Use a leading dot, which
1354 | emphasizes that the line is a method call, not a new statement.
1355 |
1356 | ```javascript
1357 | // bad
1358 | $('#items').find('.selected').highlight().end().find('.open').updateCount();
1359 |
1360 | // bad
1361 | $('#items').
1362 | find('.selected').
1363 | highlight().
1364 | end().
1365 | find('.open').
1366 | updateCount();
1367 |
1368 | // good
1369 | $('#items')
1370 | .find('.selected')
1371 | .highlight()
1372 | .end()
1373 | .find('.open')
1374 | .updateCount();
1375 |
1376 | // bad
1377 | const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
1378 | .attr('width', (radius + margin) * 2).append('svg:g')
1379 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
1380 | .call(tron.led);
1381 |
1382 | // good
1383 | const leds = stage.selectAll('.led')
1384 | .data(data)
1385 | .enter().append('svg:svg')
1386 | .classed('led', true)
1387 | .attr('width', (radius + margin) * 2)
1388 | .append('svg:g')
1389 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
1390 | .call(tron.led);
1391 | ```
1392 |
1393 | - [18.6](#18.6) Leave a blank line after blocks and before the next statement.
1394 |
1395 | ```javascript
1396 | // bad
1397 | if (foo) {
1398 | return bar;
1399 | }
1400 | return baz;
1401 |
1402 | // good
1403 | if (foo) {
1404 | return bar;
1405 | }
1406 |
1407 | return baz;
1408 |
1409 | // bad
1410 | const obj = {
1411 | foo() {
1412 | },
1413 | bar() {
1414 | },
1415 | };
1416 | return obj;
1417 |
1418 | // good
1419 | const obj = {
1420 | foo() {
1421 | },
1422 |
1423 | bar() {
1424 | },
1425 | };
1426 |
1427 | return obj;
1428 | ```
1429 |
1430 |
1431 | **[⬆ 返回目录](#table-of-contents)**
1432 |
1433 | ## Commas
1434 |
1435 | - [19.1](#19.1) Leading commas: **Nope.**
1436 |
1437 | ```javascript
1438 | // bad
1439 | const story = [
1440 | once
1441 | , upon
1442 | , aTime
1443 | ];
1444 |
1445 | // good
1446 | const story = [
1447 | once,
1448 | upon,
1449 | aTime,
1450 | ];
1451 |
1452 | // bad
1453 | const hero = {
1454 | firstName: 'Ada'
1455 | , lastName: 'Lovelace'
1456 | , birthYear: 1815
1457 | , superPower: 'computers'
1458 | };
1459 |
1460 | // good
1461 | const hero = {
1462 | firstName: 'Ada',
1463 | lastName: 'Lovelace',
1464 | birthYear: 1815,
1465 | superPower: 'computers',
1466 | };
1467 | ```
1468 |
1469 | - [19.2](#19.2) Additional trailing comma: **Yup.**
1470 |
1471 | > 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.
1472 |
1473 | ```javascript
1474 | // bad - git diff without trailing comma
1475 | const hero = {
1476 | firstName: 'Florence',
1477 | - lastName: 'Nightingale'
1478 | + lastName: 'Nightingale',
1479 | + inventorOf: ['coxcomb graph', 'modern nursing']
1480 | }
1481 |
1482 | // good - git diff with trailing comma
1483 | const hero = {
1484 | firstName: 'Florence',
1485 | lastName: 'Nightingale',
1486 | + inventorOf: ['coxcomb chart', 'modern nursing'],
1487 | }
1488 |
1489 | // bad
1490 | const hero = {
1491 | firstName: 'Dana',
1492 | lastName: 'Scully'
1493 | };
1494 |
1495 | const heroes = [
1496 | 'Batman',
1497 | 'Superman'
1498 | ];
1499 |
1500 | // good
1501 | const hero = {
1502 | firstName: 'Dana',
1503 | lastName: 'Scully',
1504 | };
1505 |
1506 | const heroes = [
1507 | 'Batman',
1508 | 'Superman',
1509 | ];
1510 | ```
1511 |
1512 | **[⬆ 返回目录](#table-of-contents)**
1513 |
1514 |
1515 | ## Semicolons
1516 |
1517 | - [20.1](#20.1) **Yup.**
1518 |
1519 | ```javascript
1520 | // bad
1521 | (function() {
1522 | const name = 'Skywalker'
1523 | return name
1524 | })()
1525 |
1526 | // good
1527 | (() => {
1528 | const name = 'Skywalker';
1529 | return name;
1530 | })();
1531 |
1532 | // good (guards against the function becoming an argument when two files with IIFEs are concatenated)
1533 | ;(() => {
1534 | const name = 'Skywalker';
1535 | return name;
1536 | })();
1537 | ```
1538 |
1539 | [Read more](http://stackoverflow.com/a/7365214/1712802).
1540 |
1541 | **[⬆ 返回目录](#table-of-contents)**
1542 |
1543 |
1544 | ## Type Casting & Coercion
1545 |
1546 | - [21.1](#21.1) Perform type coercion at the beginning of the statement.
1547 | - [21.2](#21.2) Strings:
1548 |
1549 | ```javascript
1550 | // => this.reviewScore = 9;
1551 |
1552 | // bad
1553 | const totalScore = this.reviewScore + '';
1554 |
1555 | // good
1556 | const totalScore = String(this.reviewScore);
1557 | ```
1558 |
1559 | - [21.3](#21.3) Use `parseInt` for Numbers and always with a radix for type casting.
1560 |
1561 | ```javascript
1562 | const inputValue = '4';
1563 |
1564 | // bad
1565 | const val = new Number(inputValue);
1566 |
1567 | // bad
1568 | const val = +inputValue;
1569 |
1570 | // bad
1571 | const val = inputValue >> 0;
1572 |
1573 | // bad
1574 | const val = parseInt(inputValue);
1575 |
1576 | // good
1577 | const val = Number(inputValue);
1578 |
1579 | // good
1580 | const val = parseInt(inputValue, 10);
1581 | ```
1582 |
1583 | - [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.
1584 |
1585 | ```javascript
1586 | // good
1587 | /**
1588 | * parseInt was the reason my code was slow.
1589 | * Bitshifting the String to coerce it to a
1590 | * Number made it a lot faster.
1591 | */
1592 | const val = inputValue >> 0;
1593 | ```
1594 |
1595 | - [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:
1596 |
1597 | ```javascript
1598 | 2147483647 >> 0 //=> 2147483647
1599 | 2147483648 >> 0 //=> -2147483648
1600 | 2147483649 >> 0 //=> -2147483647
1601 | ```
1602 |
1603 | - [21.6](#21.6) Booleans:
1604 |
1605 | ```javascript
1606 | const age = 0;
1607 |
1608 | // bad
1609 | const hasAge = new Boolean(age);
1610 |
1611 | // good
1612 | const hasAge = Boolean(age);
1613 |
1614 | // good
1615 | const hasAge = !!age;
1616 | ```
1617 |
1618 | **[⬆ 返回目录](#table-of-contents)**
1619 |
1620 |
1621 | ## Naming Conventions
1622 |
1623 | - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming.
1624 |
1625 | ```javascript
1626 | // bad
1627 | function q() {
1628 | // ...stuff...
1629 | }
1630 |
1631 | // good
1632 | function query() {
1633 | // ..stuff..
1634 | }
1635 | ```
1636 |
1637 | - [22.2](#22.2) Use camelCase when naming objects, functions, and instances.
1638 |
1639 | ```javascript
1640 | // bad
1641 | const OBJEcttsssss = {};
1642 | const this_is_my_object = {};
1643 | function c() {}
1644 |
1645 | // good
1646 | const thisIsMyObject = {};
1647 | function thisIsMyFunction() {}
1648 | ```
1649 |
1650 | - [22.3](#22.3) Use PascalCase when naming constructors or classes.
1651 |
1652 | ```javascript
1653 | // bad
1654 | function user(options) {
1655 | this.name = options.name;
1656 | }
1657 |
1658 | const bad = new user({
1659 | name: 'nope',
1660 | });
1661 |
1662 | // good
1663 | class User {
1664 | constructor(options) {
1665 | this.name = options.name;
1666 | }
1667 | }
1668 |
1669 | const good = new User({
1670 | name: 'yup',
1671 | });
1672 | ```
1673 |
1674 | - [22.4](#22.4) Use a leading underscore `_` when naming private properties.
1675 |
1676 | ```javascript
1677 | // bad
1678 | this.__firstName__ = 'Panda';
1679 | this.firstName_ = 'Panda';
1680 |
1681 | // good
1682 | this._firstName = 'Panda';
1683 | ```
1684 |
1685 | - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind.
1686 |
1687 | ```javascript
1688 | // bad
1689 | function foo() {
1690 | const self = this;
1691 | return function() {
1692 | console.log(self);
1693 | };
1694 | }
1695 |
1696 | // bad
1697 | function foo() {
1698 | const that = this;
1699 | return function() {
1700 | console.log(that);
1701 | };
1702 | }
1703 |
1704 | // good
1705 | function foo() {
1706 | return () => {
1707 | console.log(this);
1708 | };
1709 | }
1710 | ```
1711 |
1712 | - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class.
1713 | ```javascript
1714 | // file contents
1715 | class CheckBox {
1716 | // ...
1717 | }
1718 | export default CheckBox;
1719 |
1720 | // in some other file
1721 | // bad
1722 | import CheckBox from './checkBox';
1723 |
1724 | // bad
1725 | import CheckBox from './check_box';
1726 |
1727 | // good
1728 | import CheckBox from './CheckBox';
1729 | ```
1730 |
1731 | - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name.
1732 |
1733 | ```javascript
1734 | function makeStyleGuide() {
1735 | }
1736 |
1737 | export default makeStyleGuide;
1738 | ```
1739 |
1740 | - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object.
1741 |
1742 | ```javascript
1743 | const AirbnbStyleGuide = {
1744 | es6: {
1745 | }
1746 | };
1747 |
1748 | export default AirbnbStyleGuide;
1749 | ```
1750 |
1751 |
1752 | **[⬆ 返回目录](#table-of-contents)**
1753 |
1754 |
1755 | ## Accessors
1756 |
1757 | - [23.1](#23.1) Accessor functions for properties are not required.
1758 | - [23.2](#23.2) If you do make accessor functions use getVal() and setVal('hello').
1759 |
1760 | ```javascript
1761 | // bad
1762 | dragon.age();
1763 |
1764 | // good
1765 | dragon.getAge();
1766 |
1767 | // bad
1768 | dragon.age(25);
1769 |
1770 | // good
1771 | dragon.setAge(25);
1772 | ```
1773 |
1774 | - [23.3](#23.3) If the property is a `boolean`, use `isVal()` or `hasVal()`.
1775 |
1776 | ```javascript
1777 | // bad
1778 | if (!dragon.age()) {
1779 | return false;
1780 | }
1781 |
1782 | // good
1783 | if (!dragon.hasAge()) {
1784 | return false;
1785 | }
1786 | ```
1787 |
1788 | - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent.
1789 |
1790 | ```javascript
1791 | class Jedi {
1792 | constructor(options = {}) {
1793 | const lightsaber = options.lightsaber || 'blue';
1794 | this.set('lightsaber', lightsaber);
1795 | }
1796 |
1797 | set(key, val) {
1798 | this[key] = val;
1799 | }
1800 |
1801 | get(key) {
1802 | return this[key];
1803 | }
1804 | }
1805 | ```
1806 |
1807 | **[⬆ 返回目录](#table-of-contents)**
1808 |
1809 |
1810 | ## Events
1811 |
1812 | - [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:
1813 |
1814 | ```javascript
1815 | // bad
1816 | $(this).trigger('listingUpdated', listing.id);
1817 |
1818 | ...
1819 |
1820 | $(this).on('listingUpdated', function(e, listingId) {
1821 | // do something with listingId
1822 | });
1823 | ```
1824 |
1825 | prefer:
1826 |
1827 | ```javascript
1828 | // good
1829 | $(this).trigger('listingUpdated', { listingId : listing.id });
1830 |
1831 | ...
1832 |
1833 | $(this).on('listingUpdated', function(e, data) {
1834 | // do something with data.listingId
1835 | });
1836 | ```
1837 |
1838 | **[⬆ 返回目录
1839 | ](#table-of-contents)**
1840 |
1841 |
1842 | ## jQuery
1843 |
1844 | - [25.1](#25.1) Prefix jQuery object variables with a `$`.
1845 |
1846 | ```javascript
1847 | // bad
1848 | const sidebar = $('.sidebar');
1849 |
1850 | // good
1851 | const $sidebar = $('.sidebar');
1852 | ```
1853 |
1854 | - [25.2](#25.2) Cache jQuery lookups.
1855 |
1856 | ```javascript
1857 | // bad
1858 | function setSidebar() {
1859 | $('.sidebar').hide();
1860 |
1861 | // ...stuff...
1862 |
1863 | $('.sidebar').css({
1864 | 'background-color': 'pink'
1865 | });
1866 | }
1867 |
1868 | // good
1869 | function setSidebar() {
1870 | const $sidebar = $('.sidebar');
1871 | $sidebar.hide();
1872 |
1873 | // ...stuff...
1874 |
1875 | $sidebar.css({
1876 | 'background-color': 'pink'
1877 | });
1878 | }
1879 | ```
1880 |
1881 | - [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)
1882 | - [25.4](#25.4) Use `find` with scoped jQuery object queries.
1883 |
1884 | ```javascript
1885 | // bad
1886 | $('ul', '.sidebar').hide();
1887 |
1888 | // bad
1889 | $('.sidebar').find('ul').hide();
1890 |
1891 | // good
1892 | $('.sidebar ul').hide();
1893 |
1894 | // good
1895 | $('.sidebar > ul').hide();
1896 |
1897 | // good
1898 | $sidebar.find('ul').hide();
1899 | ```
1900 |
1901 | **[⬆ 返回目录](#table-of-contents)**
1902 |
1903 |
1904 | ## ECMAScript 5 Compatibility
1905 |
1906 | - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/).
1907 |
1908 | **[⬆ 返回目录](#table-of-contents)**
1909 |
1910 | ## ECMAScript 6 Styles
1911 |
1912 | - [27.1](#27.1) This is a collection of links to the various es6 features.
1913 |
1914 | 1. [Arrow Functions](#arrow-functions)
1915 | 1. [Classes](#constructors)
1916 | 1. [Object Shorthand](#es6-object-shorthand)
1917 | 1. [Object Concise](#es6-object-concise)
1918 | 1. [Object Computed Properties](#es6-computed-properties)
1919 | 1. [Template Strings](#es6-template-literals)
1920 | 1. [Destructuring](#destructuring)
1921 | 1. [Default Parameters](#es6-default-parameters)
1922 | 1. [Rest](#es6-rest)
1923 | 1. [Array Spreads](#es6-array-spreads)
1924 | 1. [Let and Const](#references)
1925 | 1. [Iterators and Generators](#iterators-and-generators)
1926 | 1. [Modules](#modules)
1927 |
1928 | **[⬆ 返回目录](#table-of-contents)**
1929 |
1930 | ## Testing
1931 |
1932 | - [28.1](#28.1) **Yup.**
1933 |
1934 | ```javascript
1935 | function() {
1936 | return true;
1937 | }
1938 | ```
1939 |
1940 | **[⬆ 返回目录](#table-of-contents)**
1941 |
1942 |
1943 | ## Performance
1944 |
1945 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
1946 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
1947 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
1948 | - [Bang Function](http://jsperf.com/bang-function)
1949 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
1950 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
1951 | - [Long String Concatenation](http://jsperf.com/ya-string-concat)
1952 | - Loading...
1953 |
1954 | **[⬆ 返回目录](#table-of-contents)**
1955 |
1956 |
1957 | ## Resources
1958 |
1959 | **Learning ES6**
1960 |
1961 | - [Draft ECMA 2015 (ES6) Spec](https://people.mozilla.org/~jorendorff/es6-draft.html)
1962 | - [ExploringJS](http://exploringjs.com/)
1963 | - [ES6 Compatibility Table](https://kangax.github.io/compat-table/es6/)
1964 | - [Comprehensive Overview of ES6 Features](http://es6-features.org/)
1965 |
1966 | **Read This**
1967 |
1968 | - [Annotated ECMAScript 5.1](http://es5.github.com/)
1969 |
1970 | **Tools**
1971 |
1972 | - Code Style Linters
1973 | + [ESlint](http://eslint.org/) - [Airbnb Style .eslintrc](https://github.com/airbnb/javascript/blob/master/linters/.eslintrc)
1974 | + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/jshintrc)
1975 | + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
1976 |
1977 | **Other Style Guides**
1978 |
1979 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
1980 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
1981 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
1982 |
1983 | **Other Styles**
1984 |
1985 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
1986 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
1987 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
1988 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
1989 |
1990 | **Further Reading**
1991 |
1992 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
1993 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
1994 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
1995 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
1996 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
1997 |
1998 | **Books**
1999 |
2000 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
2001 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
2002 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
2003 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
2004 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
2005 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
2006 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
2007 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
2008 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
2009 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
2010 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
2011 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
2012 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
2013 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
2014 | - [Eloquent JavaScript](http://eloquentjavascript.net/) - Marijn Haverbeke
2015 |
2016 | **Blogs**
2017 |
2018 | - [DailyJS](http://dailyjs.com/)
2019 | - [JavaScript Weekly](http://javascriptweekly.com/)
2020 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
2021 | - [Bocoup Weblog](http://weblog.bocoup.com/)
2022 | - [Adequately Good](http://www.adequatelygood.com/)
2023 | - [NCZOnline](http://www.nczonline.net/)
2024 | - [Perfection Kills](http://perfectionkills.com/)
2025 | - [Ben Alman](http://benalman.com/)
2026 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
2027 | - [Dustin Diaz](http://dustindiaz.com/)
2028 | - [nettuts](http://net.tutsplus.com/?s=javascript)
2029 |
2030 | **Podcasts**
2031 |
2032 | - [JavaScript Jabber](http://devchat.tv/js-jabber/)
2033 |
2034 |
2035 | **[⬆ 返回目录](#table-of-contents)**
2036 |
2037 | ## In the Wild
2038 |
2039 | 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.
2040 |
2041 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
2042 | - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
2043 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
2044 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
2045 | - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
2046 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
2047 | - **Blendle**: [blendle/javascript](https://github.com/blendle/javascript)
2048 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
2049 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
2050 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
2051 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
2052 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
2053 | - **Expensify** [Expensify/Style-Guide](https://github.com/Expensify/Style-Guide/blob/master/javascript.md)
2054 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
2055 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
2056 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
2057 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
2058 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
2059 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
2060 | - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
2061 | - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
2062 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
2063 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
2064 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
2065 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
2066 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
2067 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
2068 | - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
2069 | - **Muber**: [muber/javascript](https://github.com/muber/javascript)
2070 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
2071 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
2072 | - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
2073 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
2074 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
2075 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
2076 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
2077 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
2078 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
2079 | - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
2080 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
2081 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
2082 | - **Target**: [target/javascript](https://github.com/target/javascript)
2083 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
2084 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
2085 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
2086 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
2087 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
2088 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
2089 |
2090 | **[⬆ 返回目录](#table-of-contents)**
2091 |
2092 | ## Translation
2093 |
2094 | This style guide is also available in other languages:
2095 |
2096 | -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
2097 | -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
2098 | -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
2099 | -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
2100 | -  **Chinese(Simplified)**: [sivan/javascript-style-guide](https://github.com/sivan/javascript-style-guide)
2101 | -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
2102 | -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
2103 | -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
2104 | -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
2105 | -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
2106 | -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
2107 | -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
2108 | -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
2109 | -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
2110 |
2111 | ## The JavaScript Style Guide Guide
2112 |
2113 | - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
2114 |
2115 | ## Chat With Us About JavaScript
2116 |
2117 | - Find us on [gitter](https://gitter.im/airbnb/javascript).
2118 |
2119 | ## Contributors
2120 |
2121 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
2122 |
2123 |
2124 | ## License
2125 |
2126 | (The MIT License)
2127 |
2128 | Copyright (c) 2014 Airbnb
2129 |
2130 | Permission is hereby granted, free of charge, to any person obtaining
2131 | a copy of this software and associated documentation files (the
2132 | 'Software'), to deal in the Software without restriction, including
2133 | without limitation the rights to use, copy, modify, merge, publish,
2134 | distribute, sublicense, and/or sell copies of the Software, and to
2135 | permit persons to whom the Software is furnished to do so, subject to
2136 | the following conditions:
2137 |
2138 | The above copyright notice and this permission notice shall be
2139 | included in all copies or substantial portions of the Software.
2140 |
2141 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
2142 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2143 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2144 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
2145 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2146 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2147 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2148 |
2149 | **[⬆ 返回目录](#table-of-contents)**
2150 |
2151 | # };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |