├── README.md
├── LICENSE
└── es5
└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | # Airbnb JavaScript Style Guide
2 |
3 | *用更合理的方式写 JavaScript*
4 |
5 | ## [《Airbnb JavaScript Style Guide 中文版》](es5/README.md)
6 |
7 | 重新翻译了最常用的 ES5 版,同步更新英文版改动。
8 |
9 | ---
10 |
11 | 相关链接:
12 |
13 | - [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript)
14 | - [ES6/ES2015 版](https://github.com/yuche/javascript)
15 | - [React/JSX 版](https://github.com/JasonBoy/javascript/tree/master/react)
16 |
17 | -- EOF --
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sivan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/es5/README.md:
--------------------------------------------------------------------------------
1 | # Airbnb JavaScript Style Guide() {
2 |
3 | *用更合理的方式写 JavaScript*
4 |
5 | ## 目录
6 |
7 | 1. [类型](#types)
8 | 1. [对象](#objects)
9 | 1. [数组](#arrays)
10 | 1. [字符串](#strings)
11 | 1. [函数](#functions)
12 | 1. [属性](#properties)
13 | 1. [变量](#variables)
14 | 1. [提升](#hoisting)
15 | 1. [比较运算符 & 等号](#comparison-operators--equality)
16 | 1. [块](#blocks)
17 | 1. [注释](#comments)
18 | 1. [空白](#whitespace)
19 | 1. [逗号](#commas)
20 | 1. [分号](#semicolons)
21 | 1. [类型转化](#type-casting--coercion)
22 | 1. [命名规则](#naming-conventions)
23 | 1. [存取器](#accessors)
24 | 1. [构造函数](#constructors)
25 | 1. [事件](#events)
26 | 1. [模块](#modules)
27 | 1. [jQuery](#jquery)
28 | 1. [ECMAScript 5 兼容性](#ecmascript-5-compatibility)
29 | 1. [测试](#testing)
30 | 1. [性能](#performance)
31 | 1. [资源](#resources)
32 | 1. [谁在使用](#in-the-wild)
33 | 1. [翻译](#translation)
34 | 1. [JavaScript 风格指南说明](#the-javascript-style-guide-guide)
35 | 1. [与我们讨论 JavaScript](#chat-with-us-about-javascript)
36 | 1. [贡献者](#contributors)
37 | 1. [许可](#license)
38 |
39 | ## 类型
40 |
41 | - **原始值**: 存取直接作用于它自身。
42 |
43 | + `string`
44 | + `number`
45 | + `boolean`
46 | + `null`
47 | + `undefined`
48 |
49 | ```javascript
50 | var foo = 1;
51 | var bar = foo;
52 |
53 | bar = 9;
54 |
55 | console.log(foo, bar); // => 1, 9
56 | ```
57 | - **复杂类型**: 存取时作用于它自身值的引用。
58 |
59 | + `object`
60 | + `array`
61 | + `function`
62 |
63 | ```javascript
64 | var foo = [1, 2];
65 | var bar = foo;
66 |
67 | bar[0] = 9;
68 |
69 | console.log(foo[0], bar[0]); // => 9, 9
70 | ```
71 |
72 | **[⬆ 回到顶部](#table-of-contents)**
73 |
74 | ## 对象
75 |
76 | - 使用直接量创建对象。
77 |
78 | ```javascript
79 | // bad
80 | var item = new Object();
81 |
82 | // good
83 | var item = {};
84 | ```
85 |
86 | - 不要使用[保留字](http://es5.github.io/#x7.6.1)作为键名,它们在 IE8 下不工作。[更多信息](https://github.com/airbnb/javascript/issues/61)。
87 |
88 | ```javascript
89 | // bad
90 | var superman = {
91 | default: { clark: 'kent' },
92 | private: true
93 | };
94 |
95 | // good
96 | var superman = {
97 | defaults: { clark: 'kent' },
98 | hidden: true
99 | };
100 | ```
101 |
102 | - 使用同义词替换需要使用的保留字。
103 |
104 | ```javascript
105 | // bad
106 | var superman = {
107 | class: 'alien'
108 | };
109 |
110 | // bad
111 | var superman = {
112 | klass: 'alien'
113 | };
114 |
115 | // good
116 | var superman = {
117 | type: 'alien'
118 | };
119 | ```
120 |
121 | **[⬆ 回到顶部](#table-of-contents)**
122 |
123 | ## 数组
124 |
125 | - 使用直接量创建数组。
126 |
127 | ```javascript
128 | // bad
129 | var items = new Array();
130 |
131 | // good
132 | var items = [];
133 | ```
134 |
135 | - 向数组增加元素时使用 Array#push 来替代直接赋值。
136 |
137 | ```javascript
138 | var someStack = [];
139 |
140 |
141 | // bad
142 | someStack[someStack.length] = 'abracadabra';
143 |
144 | // good
145 | someStack.push('abracadabra');
146 | ```
147 |
148 | - 当你需要拷贝数组时,使用 Array#slice。[jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
149 |
150 | ```javascript
151 | var len = items.length;
152 | var itemsCopy = [];
153 | var i;
154 |
155 | // bad
156 | for (i = 0; i < len; i++) {
157 | itemsCopy[i] = items[i];
158 | }
159 |
160 | // good
161 | itemsCopy = items.slice();
162 | ```
163 |
164 | - 使用 Array#slice 将类数组对象转换成数组。
165 |
166 | ```javascript
167 | function trigger() {
168 | var args = Array.prototype.slice.call(arguments);
169 | ...
170 | }
171 | ```
172 |
173 | **[⬆ 回到顶部](#table-of-contents)**
174 |
175 |
176 | ## 字符串
177 |
178 | - 使用单引号 `''` 包裹字符串。
179 |
180 | ```javascript
181 | // bad
182 | var name = "Bob Parr";
183 |
184 | // good
185 | var name = 'Bob Parr';
186 |
187 | // bad
188 | var fullName = "Bob " + this.lastName;
189 |
190 | // good
191 | var fullName = 'Bob ' + this.lastName;
192 | ```
193 |
194 | - 超过 100 个字符的字符串应该使用连接符写成多行。
195 | - 注:若过度使用,通过连接符连接的长字符串可能会影响性能。[jsPerf](http://jsperf.com/ya-string-concat) & [讨论](https://github.com/airbnb/javascript/issues/40).
196 |
197 | ```javascript
198 | // bad
199 | 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.';
200 |
201 | // bad
202 | var errorMessage = 'This is a super long error that was thrown because \
203 | of Batman. When you stop to think about how Batman had anything to do \
204 | with this, you would get nowhere \
205 | fast.';
206 |
207 | // good
208 | var errorMessage = 'This is a super long error that was thrown because ' +
209 | 'of Batman. When you stop to think about how Batman had anything to do ' +
210 | 'with this, you would get nowhere fast.';
211 | ```
212 |
213 | - 程序化生成的字符串使用 Array#join 连接而不是使用连接符。尤其是 IE 下:[jsPerf](http://jsperf.com/string-vs-array-concat/2).
214 |
215 | ```javascript
216 | var items;
217 | var messages;
218 | var length;
219 | var i;
220 |
221 | messages = [{
222 | state: 'success',
223 | message: 'This one worked.'
224 | }, {
225 | state: 'success',
226 | message: 'This one worked as well.'
227 | }, {
228 | state: 'error',
229 | message: 'This one did not work.'
230 | }];
231 |
232 | length = messages.length;
233 |
234 | // bad
235 | function inbox(messages) {
236 | items = '
';
237 |
238 | for (i = 0; i < length; i++) {
239 | items += '- ' + messages[i].message + '
';
240 | }
241 |
242 | return items + '
';
243 | }
244 |
245 | // good
246 | function inbox(messages) {
247 | items = [];
248 |
249 | for (i = 0; i < length; i++) {
250 | // use direct assignment in this case because we're micro-optimizing.
251 | items[i] = '' + messages[i].message + '';
252 | }
253 |
254 | return '';
255 | }
256 | ```
257 |
258 | **[⬆ 回到顶部](#table-of-contents)**
259 |
260 |
261 | ## 函数
262 |
263 | - 函数表达式:
264 |
265 | ```javascript
266 | // 匿名函数表达式
267 | var anonymous = function() {
268 | return true;
269 | };
270 |
271 | // 命名函数表达式
272 | var named = function named() {
273 | return true;
274 | };
275 |
276 | // 立即调用的函数表达式(IIFE)
277 | (function () {
278 | console.log('Welcome to the Internet. Please follow me.');
279 | }());
280 | ```
281 |
282 | - 永远不要在一个非函数代码块(if、while 等)中声明一个函数,浏览器允许你这么做,但它们的解析表现不一致,正确的做法是:在块外定义一个变量,然后将函数赋值给它。
283 | - **注:** ECMA-262 把 `块` 定义为一组语句。函数声明不是语句。[阅读对 ECMA-262 这个问题的说明](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97)。
284 |
285 | ```javascript
286 | // bad
287 | if (currentUser) {
288 | function test() {
289 | console.log('Nope.');
290 | }
291 | }
292 |
293 | // good
294 | var test;
295 | if (currentUser) {
296 | test = function test() {
297 | console.log('Yup.');
298 | };
299 | }
300 | ```
301 |
302 | - 永远不要把参数命名为 `arguments`。这将取代函数作用域内的 `arguments` 对象。
303 |
304 | ```javascript
305 | // bad
306 | function nope(name, options, arguments) {
307 | // ...stuff...
308 | }
309 |
310 | // good
311 | function yup(name, options, args) {
312 | // ...stuff...
313 | }
314 | ```
315 |
316 | **[⬆ 回到顶部](#table-of-contents)**
317 |
318 |
319 |
320 | ## 属性
321 |
322 | - 使用 `.` 来访问对象的属性。
323 |
324 | ```javascript
325 | var luke = {
326 | jedi: true,
327 | age: 28
328 | };
329 |
330 | // bad
331 | var isJedi = luke['jedi'];
332 |
333 | // good
334 | var isJedi = luke.jedi;
335 | ```
336 |
337 | - 当通过变量访问属性时使用中括号 `[]`。
338 |
339 | ```javascript
340 | var luke = {
341 | jedi: true,
342 | age: 28
343 | };
344 |
345 | function getProp(prop) {
346 | return luke[prop];
347 | }
348 |
349 | var isJedi = getProp('jedi');
350 | ```
351 |
352 | **[⬆ 回到顶部](#table-of-contents)**
353 |
354 |
355 | ## 变量
356 |
357 | - 总是使用 `var` 来声明变量。不这么做将导致产生全局变量。我们要避免污染全局命名空间。
358 |
359 | ```javascript
360 | // bad
361 | superPower = new SuperPower();
362 |
363 | // good
364 | var superPower = new SuperPower();
365 | ```
366 |
367 | - 使用 `var` 声明每一个变量。
368 | 这样做的好处是增加新变量将变的更加容易,而且你永远不用再担心调换错 `;` 跟 `,`。
369 |
370 | ```javascript
371 | // bad
372 | var items = getItems(),
373 | goSportsTeam = true,
374 | dragonball = 'z';
375 |
376 | // bad
377 | // (跟上面的代码比较一下,看看哪里错了)
378 | var items = getItems(),
379 | goSportsTeam = true;
380 | dragonball = 'z';
381 |
382 | // good
383 | var items = getItems();
384 | var goSportsTeam = true;
385 | var dragonball = 'z';
386 | ```
387 |
388 | - 最后再声明未赋值的变量。当你需要引用前面的变量赋值时这将变的很有用。
389 |
390 | ```javascript
391 | // bad
392 | var i, len, dragonball,
393 | items = getItems(),
394 | goSportsTeam = true;
395 |
396 | // bad
397 | var i;
398 | var items = getItems();
399 | var dragonball;
400 | var goSportsTeam = true;
401 | var len;
402 |
403 | // good
404 | var items = getItems();
405 | var goSportsTeam = true;
406 | var dragonball;
407 | var length;
408 | var i;
409 | ```
410 |
411 | - 在作用域顶部声明变量。这将帮你避免变量声明提升相关的问题。
412 |
413 | ```javascript
414 | // bad
415 | function () {
416 | test();
417 | console.log('doing stuff..');
418 |
419 | //..other stuff..
420 |
421 | var name = getName();
422 |
423 | if (name === 'test') {
424 | return false;
425 | }
426 |
427 | return name;
428 | }
429 |
430 | // good
431 | function () {
432 | var name = getName();
433 |
434 | test();
435 | console.log('doing stuff..');
436 |
437 | //..other stuff..
438 |
439 | if (name === 'test') {
440 | return false;
441 | }
442 |
443 | return name;
444 | }
445 |
446 | // bad - 不必要的函数调用
447 | function () {
448 | var name = getName();
449 |
450 | if (!arguments.length) {
451 | return false;
452 | }
453 |
454 | this.setFirstName(name);
455 |
456 | return true;
457 | }
458 |
459 | // good
460 | function () {
461 | var name;
462 |
463 | if (!arguments.length) {
464 | return false;
465 | }
466 |
467 | name = getName();
468 | this.setFirstName(name);
469 |
470 | return true;
471 | }
472 | ```
473 |
474 | **[⬆ 回到顶部](#table-of-contents)**
475 |
476 |
477 | ## 提升
478 |
479 | - 变量声明会提升至作用域顶部,但赋值不会。
480 |
481 | ```javascript
482 | // 我们知道这样不能正常工作(假设这里没有名为 notDefined 的全局变量)
483 | function example() {
484 | console.log(notDefined); // => throws a ReferenceError
485 | }
486 |
487 | // 但由于变量声明提升的原因,在一个变量引用后再创建它的变量声明将可以正常工作。
488 | // 注:变量赋值为 `true` 不会提升。
489 | function example() {
490 | console.log(declaredButNotAssigned); // => undefined
491 | var declaredButNotAssigned = true;
492 | }
493 |
494 | // 解释器会把变量声明提升到作用域顶部,意味着我们的例子将被重写成:
495 | function example() {
496 | var declaredButNotAssigned;
497 | console.log(declaredButNotAssigned); // => undefined
498 | declaredButNotAssigned = true;
499 | }
500 | ```
501 |
502 | - 匿名函数表达式会提升它们的变量名,但不会提升函数的赋值。
503 |
504 | ```javascript
505 | function example() {
506 | console.log(anonymous); // => undefined
507 |
508 | anonymous(); // => TypeError anonymous is not a function
509 |
510 | var anonymous = function () {
511 | console.log('anonymous function expression');
512 | };
513 | }
514 | ```
515 |
516 | - 命名函数表达式会提升变量名,但不会提升函数名或函数体。
517 |
518 | ```javascript
519 | function example() {
520 | console.log(named); // => undefined
521 |
522 | named(); // => TypeError named is not a function
523 |
524 | superPower(); // => ReferenceError superPower is not defined
525 |
526 | var named = function superPower() {
527 | console.log('Flying');
528 | };
529 | }
530 |
531 | // 当函数名跟变量名一样时,表现也是如此。
532 | function example() {
533 | console.log(named); // => undefined
534 |
535 | named(); // => TypeError named is not a function
536 |
537 | var named = function named() {
538 | console.log('named');
539 | }
540 | }
541 | ```
542 |
543 | - 函数声明提升它们的名字和函数体。
544 |
545 | ```javascript
546 | function example() {
547 | superPower(); // => Flying
548 |
549 | function superPower() {
550 | console.log('Flying');
551 | }
552 | }
553 | ```
554 |
555 | - 了解更多信息在 [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/).
556 |
557 | **[⬆ 回到顶部](#table-of-contents)**
558 |
559 |
560 |
561 | ## 比较运算符 & 等号
562 |
563 | - 优先使用 `===` 和 `!==` 而不是 `==` 和 `!=`.
564 | - 条件表达式例如 `if` 语句通过抽象方法 `ToBoolean` 强制计算它们的表达式并且总是遵守下面的规则:
565 |
566 | + **对象** 被计算为 **true**
567 | + **Undefined** 被计算为 **false**
568 | + **Null** 被计算为 **false**
569 | + **布尔值** 被计算为 **布尔的值**
570 | + **数字** 如果是 **+0、-0 或 NaN** 被计算为 **false**,否则为 **true**
571 | + **字符串** 如果是空字符串 `''` 被计算为 **false**,否则为 **true**
572 |
573 | ```javascript
574 | if ([0]) {
575 | // true
576 | // 一个数组就是一个对象,对象被计算为 true
577 | }
578 | ```
579 |
580 | - 使用快捷方式。
581 |
582 | ```javascript
583 | // bad
584 | if (name !== '') {
585 | // ...stuff...
586 | }
587 |
588 | // good
589 | if (name) {
590 | // ...stuff...
591 | }
592 |
593 | // bad
594 | if (collection.length > 0) {
595 | // ...stuff...
596 | }
597 |
598 | // good
599 | if (collection.length) {
600 | // ...stuff...
601 | }
602 | ```
603 |
604 | - 了解更多信息在 [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll.
605 |
606 | **[⬆ 回到顶部](#table-of-contents)**
607 |
608 |
609 | ## 块
610 |
611 | - 使用大括号包裹所有的多行代码块。
612 |
613 | ```javascript
614 | // bad
615 | if (test)
616 | return false;
617 |
618 | // good
619 | if (test) return false;
620 |
621 | // good
622 | if (test) {
623 | return false;
624 | }
625 |
626 | // bad
627 | function () { return false; }
628 |
629 | // good
630 | function () {
631 | return false;
632 | }
633 | ```
634 |
635 | - 如果通过 `if` 和 `else` 使用多行代码块,把 `else` 放在 `if` 代码块关闭括号的同一行。
636 |
637 | ```javascript
638 | // bad
639 | if (test) {
640 | thing1();
641 | thing2();
642 | }
643 | else {
644 | thing3();
645 | }
646 |
647 | // good
648 | if (test) {
649 | thing1();
650 | thing2();
651 | } else {
652 | thing3();
653 | }
654 | ```
655 |
656 |
657 | **[⬆ 回到顶部](#table-of-contents)**
658 |
659 |
660 | ## 注释
661 |
662 | - 使用 `/** ... */` 作为多行注释。包含描述、指定所有参数和返回值的类型和值。
663 |
664 | ```javascript
665 | // bad
666 | // make() returns a new element
667 | // based on the passed in tag name
668 | //
669 | // @param {String} tag
670 | // @return {Element} element
671 | function make(tag) {
672 |
673 | // ...stuff...
674 |
675 | return element;
676 | }
677 |
678 | // good
679 | /**
680 | * make() returns a new element
681 | * based on the passed in tag name
682 | *
683 | * @param {String} tag
684 | * @return {Element} element
685 | */
686 | function make(tag) {
687 |
688 | // ...stuff...
689 |
690 | return element;
691 | }
692 | ```
693 |
694 | - 使用 `//` 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。
695 |
696 | ```javascript
697 | // bad
698 | var active = true; // is current tab
699 |
700 | // good
701 | // is current tab
702 | var active = true;
703 |
704 | // bad
705 | function getType() {
706 | console.log('fetching type...');
707 | // set the default type to 'no type'
708 | var type = this.type || 'no type';
709 |
710 | return type;
711 | }
712 |
713 | // good
714 | function getType() {
715 | console.log('fetching type...');
716 |
717 | // set the default type to 'no type'
718 | var type = this.type || 'no type';
719 |
720 | return type;
721 | }
722 | ```
723 |
724 | - 给注释增加 `FIXME` 或 `TODO` 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 `FIXME -- need to figure this out` 或者 `TODO -- need to implement`。
725 |
726 | - 使用 `// FIXME:` 标注问题。
727 |
728 | ```javascript
729 | function Calculator() {
730 |
731 | // FIXME: shouldn't use a global here
732 | total = 0;
733 |
734 | return this;
735 | }
736 | ```
737 |
738 | - 使用 `// TODO:` 标注问题的解决方式。
739 |
740 | ```javascript
741 | function Calculator() {
742 |
743 | // TODO: total should be configurable by an options param
744 | this.total = 0;
745 |
746 | return this;
747 | }
748 | ```
749 |
750 | **[⬆ 回到顶部](#table-of-contents)**
751 |
752 |
753 | ## 空白
754 |
755 | - 使用 2 个空格作为缩进。
756 |
757 | ```javascript
758 | // bad
759 | function () {
760 | ∙∙∙∙var name;
761 | }
762 |
763 | // bad
764 | function () {
765 | ∙var name;
766 | }
767 |
768 | // good
769 | function () {
770 | ∙∙var name;
771 | }
772 | ```
773 |
774 | - 在大括号前放一个空格。
775 |
776 | ```javascript
777 | // bad
778 | function test(){
779 | console.log('test');
780 | }
781 |
782 | // good
783 | function test() {
784 | console.log('test');
785 | }
786 |
787 | // bad
788 | dog.set('attr',{
789 | age: '1 year',
790 | breed: 'Bernese Mountain Dog'
791 | });
792 |
793 | // good
794 | dog.set('attr', {
795 | age: '1 year',
796 | breed: 'Bernese Mountain Dog'
797 | });
798 | ```
799 |
800 | - 在控制语句(`if`、`while` 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。
801 |
802 | ```javascript
803 | // bad
804 | if(isJedi) {
805 | fight ();
806 | }
807 |
808 | // good
809 | if (isJedi) {
810 | fight();
811 | }
812 |
813 | // bad
814 | function fight () {
815 | console.log ('Swooosh!');
816 | }
817 |
818 | // good
819 | function fight() {
820 | console.log('Swooosh!');
821 | }
822 | ```
823 |
824 | - 使用空格把运算符隔开。
825 |
826 | ```javascript
827 | // bad
828 | var x=y+5;
829 |
830 | // good
831 | var x = y + 5;
832 | ```
833 |
834 | - 在文件末尾插入一个空行。
835 |
836 | ```javascript
837 | // bad
838 | (function (global) {
839 | // ...stuff...
840 | })(this);
841 | ```
842 |
843 | ```javascript
844 | // bad
845 | (function (global) {
846 | // ...stuff...
847 | })(this);↵
848 | ↵
849 | ```
850 |
851 | ```javascript
852 | // good
853 | (function (global) {
854 | // ...stuff...
855 | })(this);↵
856 | ```
857 |
858 | - 在使用长方法链时进行缩进。使用前面的点 `.` 强调这是方法调用而不是新语句。
859 |
860 | ```javascript
861 | // bad
862 | $('#items').find('.selected').highlight().end().find('.open').updateCount();
863 |
864 | // bad
865 | $('#items').
866 | find('.selected').
867 | highlight().
868 | end().
869 | find('.open').
870 | updateCount();
871 |
872 | // good
873 | $('#items')
874 | .find('.selected')
875 | .highlight()
876 | .end()
877 | .find('.open')
878 | .updateCount();
879 |
880 | // bad
881 | var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
882 | .attr('width', (radius + margin) * 2).append('svg:g')
883 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
884 | .call(tron.led);
885 |
886 | // good
887 | var leds = stage.selectAll('.led')
888 | .data(data)
889 | .enter().append('svg:svg')
890 | .classed('led', true)
891 | .attr('width', (radius + margin) * 2)
892 | .append('svg:g')
893 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
894 | .call(tron.led);
895 | ```
896 |
897 | - 在块末和新语句前插入空行。
898 |
899 | ```javascript
900 | // bad
901 | if (foo) {
902 | return bar;
903 | }
904 | return baz;
905 |
906 | // good
907 | if (foo) {
908 | return bar;
909 | }
910 |
911 | return baz;
912 |
913 | // bad
914 | var obj = {
915 | foo: function () {
916 | },
917 | bar: function () {
918 | }
919 | };
920 | return obj;
921 |
922 | // good
923 | var obj = {
924 | foo: function () {
925 | },
926 |
927 | bar: function () {
928 | }
929 | };
930 |
931 | return obj;
932 | ```
933 |
934 |
935 | **[⬆ 回到顶部](#table-of-contents)**
936 |
937 | ## 逗号
938 |
939 | - 行首逗号: **不需要**。
940 |
941 | ```javascript
942 | // bad
943 | var story = [
944 | once
945 | , upon
946 | , aTime
947 | ];
948 |
949 | // good
950 | var story = [
951 | once,
952 | upon,
953 | aTime
954 | ];
955 |
956 | // bad
957 | var hero = {
958 | firstName: 'Bob'
959 | , lastName: 'Parr'
960 | , heroName: 'Mr. Incredible'
961 | , superPower: 'strength'
962 | };
963 |
964 | // good
965 | var hero = {
966 | firstName: 'Bob',
967 | lastName: 'Parr',
968 | heroName: 'Mr. Incredible',
969 | superPower: 'strength'
970 | };
971 | ```
972 |
973 | - 额外的行末逗号:**不需要**。这样做会在 IE6/7 和 IE9 怪异模式下引起问题。同样,多余的逗号在某些 ES3 的实现里会增加数组的长度。在 ES5 中已经澄清了 ([source](http://es5.github.io/#D)):
974 |
975 | > 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.
976 |
977 | ```javascript
978 | // bad
979 | var hero = {
980 | firstName: 'Kevin',
981 | lastName: 'Flynn',
982 | };
983 |
984 | var heroes = [
985 | 'Batman',
986 | 'Superman',
987 | ];
988 |
989 | // good
990 | var hero = {
991 | firstName: 'Kevin',
992 | lastName: 'Flynn'
993 | };
994 |
995 | var heroes = [
996 | 'Batman',
997 | 'Superman'
998 | ];
999 | ```
1000 |
1001 | **[⬆ 回到顶部](#table-of-contents)**
1002 |
1003 |
1004 | ## 分号
1005 |
1006 | - **使用分号。**
1007 |
1008 | ```javascript
1009 | // bad
1010 | (function () {
1011 | var name = 'Skywalker'
1012 | return name
1013 | })()
1014 |
1015 | // good
1016 | (function () {
1017 | var name = 'Skywalker';
1018 | return name;
1019 | })();
1020 |
1021 | // good (防止函数在两个 IIFE 合并时被当成一个参数
1022 | ;(function () {
1023 | var name = 'Skywalker';
1024 | return name;
1025 | })();
1026 | ```
1027 |
1028 | [了解更多](http://stackoverflow.com/a/7365214/1712802).
1029 |
1030 | **[⬆ 回到顶部](#table-of-contents)**
1031 |
1032 |
1033 | ## 类型转换
1034 |
1035 | - 在语句开始时执行类型转换。
1036 | - 字符串:
1037 |
1038 | ```javascript
1039 | // => this.reviewScore = 9;
1040 |
1041 | // bad
1042 | var totalScore = this.reviewScore + '';
1043 |
1044 | // good
1045 | var totalScore = '' + this.reviewScore;
1046 |
1047 | // bad
1048 | var totalScore = '' + this.reviewScore + ' total score';
1049 |
1050 | // good
1051 | var totalScore = this.reviewScore + ' total score';
1052 | ```
1053 |
1054 | - 使用 `parseInt` 转换数字时总是带上类型转换的基数。
1055 |
1056 | ```javascript
1057 | var inputValue = '4';
1058 |
1059 | // bad
1060 | var val = new Number(inputValue);
1061 |
1062 | // bad
1063 | var val = +inputValue;
1064 |
1065 | // bad
1066 | var val = inputValue >> 0;
1067 |
1068 | // bad
1069 | var val = parseInt(inputValue);
1070 |
1071 | // good
1072 | var val = Number(inputValue);
1073 |
1074 | // good
1075 | var val = parseInt(inputValue, 10);
1076 | ```
1077 |
1078 | - 如果因为某些原因 `parseInt` 成为你所做的事的瓶颈而需要使用位操作解决[性能问题](http://jsperf.com/coercion-vs-casting/3)时,留个注释说清楚原因和你的目的。
1079 |
1080 | ```javascript
1081 | // good
1082 | /**
1083 | * parseInt was the reason my code was slow.
1084 | * Bitshifting the String to coerce it to a
1085 | * Number made it a lot faster.
1086 | */
1087 | var val = inputValue >> 0;
1088 | ```
1089 |
1090 | - **注:** 小心使用位操作运算符。数字会被当成 [64 位值](http://es5.github.io/#x4.3.19),但是位操作运算符总是返回 32 位的整数([source](http://es5.github.io/#x11.7))。位操作处理大于 32 位的整数值时还会导致意料之外的行为。[讨论](https://github.com/airbnb/javascript/issues/109)。最大的 32 位整数是 2,147,483,647:
1091 |
1092 | ```javascript
1093 | 2147483647 >> 0 //=> 2147483647
1094 | 2147483648 >> 0 //=> -2147483648
1095 | 2147483649 >> 0 //=> -2147483647
1096 | ```
1097 |
1098 | - 布尔:
1099 |
1100 | ```javascript
1101 | var age = 0;
1102 |
1103 | // bad
1104 | var hasAge = new Boolean(age);
1105 |
1106 | // good
1107 | var hasAge = Boolean(age);
1108 |
1109 | // good
1110 | var hasAge = !!age;
1111 | ```
1112 |
1113 | **[⬆ 回到顶部](#table-of-contents)**
1114 |
1115 |
1116 | ## 命名规则
1117 |
1118 | - 避免单字母命名。命名应具备描述性。
1119 |
1120 | ```javascript
1121 | // bad
1122 | function q() {
1123 | // ...stuff...
1124 | }
1125 |
1126 | // good
1127 | function query() {
1128 | // ..stuff..
1129 | }
1130 | ```
1131 |
1132 | - 使用驼峰式命名对象、函数和实例。
1133 |
1134 | ```javascript
1135 | // bad
1136 | var OBJEcttsssss = {};
1137 | var this_is_my_object = {};
1138 | var o = {};
1139 | function c() {}
1140 |
1141 | // good
1142 | var thisIsMyObject = {};
1143 | function thisIsMyFunction() {}
1144 | ```
1145 |
1146 | - 使用帕斯卡式命名构造函数或类。
1147 |
1148 | ```javascript
1149 | // bad
1150 | function user(options) {
1151 | this.name = options.name;
1152 | }
1153 |
1154 | var bad = new user({
1155 | name: 'nope'
1156 | });
1157 |
1158 | // good
1159 | function User(options) {
1160 | this.name = options.name;
1161 | }
1162 |
1163 | var good = new User({
1164 | name: 'yup'
1165 | });
1166 | ```
1167 |
1168 | - 不要使用下划线前/后缀。
1169 |
1170 | > 为什么?JavaScript 并没有私有属性或私有方法的概念。虽然使用下划线是表示「私有」的一种共识,但实际上这些属性是完全公开的,它本身就是你公共接口的一部分。这种习惯或许会导致开发者错误的认为改动它不会造成破坏或者不需要去测试。长话短说:如果你想要某处为「私有」,它必须不能是显式提出的。
1171 |
1172 | ```javascript
1173 | // bad
1174 | this.__firstName__ = 'Panda';
1175 | this.firstName_ = 'Panda';
1176 | this._firstName = 'Panda';
1177 |
1178 | // good
1179 | this.firstName = 'Panda';
1180 | ```
1181 |
1182 | - 不要保存 `this` 的引用。使用 Function#bind。
1183 |
1184 | ```javascript
1185 | // bad
1186 | function () {
1187 | var self = this;
1188 | return function () {
1189 | console.log(self);
1190 | };
1191 | }
1192 |
1193 | // bad
1194 | function () {
1195 | var that = this;
1196 | return function () {
1197 | console.log(that);
1198 | };
1199 | }
1200 |
1201 | // bad
1202 | function () {
1203 | var _this = this;
1204 | return function () {
1205 | console.log(_this);
1206 | };
1207 | }
1208 |
1209 | // good
1210 | function () {
1211 | return function () {
1212 | console.log(this);
1213 | }.bind(this);
1214 | }
1215 | ```
1216 |
1217 | - 给函数命名。这在做堆栈轨迹时很有帮助。
1218 |
1219 | ```javascript
1220 | // bad
1221 | var log = function (msg) {
1222 | console.log(msg);
1223 | };
1224 |
1225 | // good
1226 | var log = function log(msg) {
1227 | console.log(msg);
1228 | };
1229 | ```
1230 |
1231 | - **注:** IE8 及以下版本对命名函数表达式的处理有些怪异。了解更多信息到 [http://kangax.github.io/nfe/](http://kangax.github.io/nfe/)。
1232 |
1233 | - 如果你的文件导出一个类,你的文件名应该与类名完全相同。
1234 | ```javascript
1235 | // file contents
1236 | class CheckBox {
1237 | // ...
1238 | }
1239 | module.exports = CheckBox;
1240 |
1241 | // in some other file
1242 | // bad
1243 | var CheckBox = require('./checkBox');
1244 |
1245 | // bad
1246 | var CheckBox = require('./check_box');
1247 |
1248 | // good
1249 | var CheckBox = require('./CheckBox');
1250 | ```
1251 |
1252 | **[⬆ 回到顶部](#table-of-contents)**
1253 |
1254 |
1255 | ## 存取器
1256 |
1257 | - 属性的存取函数不是必须的。
1258 | - 如果你需要存取函数时使用 `getVal()` 和 `setVal('hello')`。
1259 |
1260 | ```javascript
1261 | // bad
1262 | dragon.age();
1263 |
1264 | // good
1265 | dragon.getAge();
1266 |
1267 | // bad
1268 | dragon.age(25);
1269 |
1270 | // good
1271 | dragon.setAge(25);
1272 | ```
1273 |
1274 | - 如果属性是布尔值,使用 `isVal()` 或 `hasVal()`。
1275 |
1276 | ```javascript
1277 | // bad
1278 | if (!dragon.age()) {
1279 | return false;
1280 | }
1281 |
1282 | // good
1283 | if (!dragon.hasAge()) {
1284 | return false;
1285 | }
1286 | ```
1287 |
1288 | - 创建 get() 和 set() 函数是可以的,但要保持一致。
1289 |
1290 | ```javascript
1291 | function Jedi(options) {
1292 | options || (options = {});
1293 | var lightsaber = options.lightsaber || 'blue';
1294 | this.set('lightsaber', lightsaber);
1295 | }
1296 |
1297 | Jedi.prototype.set = function set(key, val) {
1298 | this[key] = val;
1299 | };
1300 |
1301 | Jedi.prototype.get = function get(key) {
1302 | return this[key];
1303 | };
1304 | ```
1305 |
1306 | **[⬆ 回到顶部](#table-of-contents)**
1307 |
1308 |
1309 | ## 构造函数
1310 |
1311 | - 给对象原型分配方法,而不是使用一个新对象覆盖原型。覆盖原型将导致继承出现问题:重设原型将覆盖原有原型!
1312 |
1313 | ```javascript
1314 | function Jedi() {
1315 | console.log('new jedi');
1316 | }
1317 |
1318 | // bad
1319 | Jedi.prototype = {
1320 | fight: function fight() {
1321 | console.log('fighting');
1322 | },
1323 |
1324 | block: function block() {
1325 | console.log('blocking');
1326 | }
1327 | };
1328 |
1329 | // good
1330 | Jedi.prototype.fight = function fight() {
1331 | console.log('fighting');
1332 | };
1333 |
1334 | Jedi.prototype.block = function block() {
1335 | console.log('blocking');
1336 | };
1337 | ```
1338 |
1339 | - 方法可以返回 `this` 来实现方法链式使用。
1340 |
1341 | ```javascript
1342 | // bad
1343 | Jedi.prototype.jump = function jump() {
1344 | this.jumping = true;
1345 | return true;
1346 | };
1347 |
1348 | Jedi.prototype.setHeight = function setHeight(height) {
1349 | this.height = height;
1350 | };
1351 |
1352 | var luke = new Jedi();
1353 | luke.jump(); // => true
1354 | luke.setHeight(20); // => undefined
1355 |
1356 | // good
1357 | Jedi.prototype.jump = function jump() {
1358 | this.jumping = true;
1359 | return this;
1360 | };
1361 |
1362 | Jedi.prototype.setHeight = function setHeight(height) {
1363 | this.height = height;
1364 | return this;
1365 | };
1366 |
1367 | var luke = new Jedi();
1368 |
1369 | luke.jump()
1370 | .setHeight(20);
1371 | ```
1372 |
1373 |
1374 | - 写一个自定义的 `toString()` 方法是可以的,但是确保它可以正常工作且不会产生副作用。
1375 |
1376 | ```javascript
1377 | function Jedi(options) {
1378 | options || (options = {});
1379 | this.name = options.name || 'no name';
1380 | }
1381 |
1382 | Jedi.prototype.getName = function getName() {
1383 | return this.name;
1384 | };
1385 |
1386 | Jedi.prototype.toString = function toString() {
1387 | return 'Jedi - ' + this.getName();
1388 | };
1389 | ```
1390 |
1391 | **[⬆ 回到顶部](#table-of-contents)**
1392 |
1393 |
1394 | ## 事件
1395 |
1396 | - 当给事件附加数据时(无论是 DOM 事件还是私有事件),传入一个哈希而不是原始值。这样可以让后面的贡献者增加更多数据到事件数据而无需找出并更新事件的每一个处理器。例如,不好的写法:
1397 |
1398 | ```js
1399 | // bad
1400 | $(this).trigger('listingUpdated', listing.id);
1401 |
1402 | ...
1403 |
1404 | $(this).on('listingUpdated', function (e, listingId) {
1405 | // do something with listingId
1406 | });
1407 | ```
1408 |
1409 | 更好的写法:
1410 |
1411 | ```js
1412 | // good
1413 | $(this).trigger('listingUpdated', { listingId : listing.id });
1414 |
1415 | ...
1416 |
1417 | $(this).on('listingUpdated', function (e, data) {
1418 | // do something with data.listingId
1419 | });
1420 | ```
1421 |
1422 | **[⬆ 回到顶部](#table-of-contents)**
1423 |
1424 |
1425 | ## 模块
1426 |
1427 | - 模块应该以 `!` 开始。这样确保了当一个不好的模块忘记包含最后的分号时,在合并代码到生产环境后不会产生错误。[详细说明](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)
1428 | - 文件应该以驼峰式命名,并放在同名的文件夹里,且与导出的名字一致。
1429 | - 增加一个名为 `noConflict()` 的方法来设置导出的模块为前一个版本并返回它。
1430 | - 永远在模块顶部声明 `'use strict';`。
1431 |
1432 | ```javascript
1433 | // fancyInput/fancyInput.js
1434 |
1435 | !function (global) {
1436 | 'use strict';
1437 |
1438 | var previousFancyInput = global.FancyInput;
1439 |
1440 | function FancyInput(options) {
1441 | this.options = options || {};
1442 | }
1443 |
1444 | FancyInput.noConflict = function noConflict() {
1445 | global.FancyInput = previousFancyInput;
1446 | return FancyInput;
1447 | };
1448 |
1449 | global.FancyInput = FancyInput;
1450 | }(this);
1451 | ```
1452 |
1453 | **[⬆ 回到顶部](#table-of-contents)**
1454 |
1455 |
1456 | ## jQuery
1457 |
1458 | - 使用 `$` 作为存储 jQuery 对象的变量名前缀。
1459 |
1460 | ```javascript
1461 | // bad
1462 | var sidebar = $('.sidebar');
1463 |
1464 | // good
1465 | var $sidebar = $('.sidebar');
1466 | ```
1467 |
1468 | - 缓存 jQuery 查询。
1469 |
1470 | ```javascript
1471 | // bad
1472 | function setSidebar() {
1473 | $('.sidebar').hide();
1474 |
1475 | // ...stuff...
1476 |
1477 | $('.sidebar').css({
1478 | 'background-color': 'pink'
1479 | });
1480 | }
1481 |
1482 | // good
1483 | function setSidebar() {
1484 | var $sidebar = $('.sidebar');
1485 | $sidebar.hide();
1486 |
1487 | // ...stuff...
1488 |
1489 | $sidebar.css({
1490 | 'background-color': 'pink'
1491 | });
1492 | }
1493 | ```
1494 |
1495 | - 对 DOM 查询使用层叠 `$('.sidebar ul')` 或 父元素 > 子元素 `$('.sidebar > ul')`。 [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
1496 | - 对有作用域的 jQuery 对象查询使用 `find`。
1497 |
1498 | ```javascript
1499 | // bad
1500 | $('ul', '.sidebar').hide();
1501 |
1502 | // bad
1503 | $('.sidebar').find('ul').hide();
1504 |
1505 | // good
1506 | $('.sidebar ul').hide();
1507 |
1508 | // good
1509 | $('.sidebar > ul').hide();
1510 |
1511 | // good
1512 | $sidebar.find('ul').hide();
1513 | ```
1514 |
1515 | **[⬆ 回到顶部](#table-of-contents)**
1516 |
1517 |
1518 | ## ECMAScript 5 兼容性
1519 |
1520 | - 参考 [Kangax](https://twitter.com/kangax/) 的 ES5 [兼容表](http://kangax.github.com/es5-compat-table/).
1521 |
1522 | **[⬆ 回到顶部](#table-of-contents)**
1523 |
1524 |
1525 | ## 测试
1526 |
1527 | - **Yup.**
1528 |
1529 | ```javascript
1530 | function () {
1531 | return true;
1532 | }
1533 | ```
1534 |
1535 | **[⬆ 回到顶部](#table-of-contents)**
1536 |
1537 |
1538 | ## 性能
1539 |
1540 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
1541 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
1542 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
1543 | - [Bang Function](http://jsperf.com/bang-function)
1544 | - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
1545 | - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
1546 | - [Long String Concatenation](http://jsperf.com/ya-string-concat)
1547 | - Loading...
1548 |
1549 | **[⬆ 回到顶部](#table-of-contents)**
1550 |
1551 |
1552 | ## 资源
1553 |
1554 |
1555 | **推荐阅读**
1556 |
1557 | - [Annotated ECMAScript 5.1](http://es5.github.com/)
1558 |
1559 | **工具**
1560 |
1561 | - Code Style Linters
1562 | + [JSHint](http://www.jshint.com/) - [Airbnb Style .jshintrc](https://github.com/airbnb/javascript/blob/master/linters/.jshintrc)
1563 | + [JSCS](https://github.com/jscs-dev/node-jscs) - [Airbnb Style Preset](https://github.com/jscs-dev/node-jscs/blob/master/presets/airbnb.json)
1564 |
1565 | **其它风格指南**
1566 |
1567 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
1568 | - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
1569 | - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
1570 | - [JavaScript Standard Style](https://github.com/feross/standard)
1571 |
1572 | **其它风格**
1573 |
1574 | - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
1575 | - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52) - Ross Allen
1576 | - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript) - JeongHoon Byun
1577 | - [Multiple var statements in JavaScript, not superfluous](http://benalman.com/news/2012/05/multiple-var-statements-javascript/) - Ben Alman
1578 |
1579 | **进一步阅读**
1580 |
1581 | - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
1582 | - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
1583 | - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
1584 | - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
1585 | - [Frontend Guidelines](https://github.com/bendc/frontend-guidelines) - Benjamin De Cock
1586 |
1587 | **书籍**
1588 |
1589 | - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
1590 | - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
1591 | - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
1592 | - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
1593 | - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
1594 | - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
1595 | - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
1596 | - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
1597 | - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
1598 | - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
1599 | - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
1600 | - [JSBooks](http://jsbooks.revolunet.com/) - Julien Bouquillon
1601 | - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
1602 | - [Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript](http://amzn.com/0321812182) - David Herman
1603 | - [Eloquent JavaScript](http://eloquentjavascript.net) - Marijn Haverbeke
1604 | - [You Don't Know JS](https://github.com/getify/You-Dont-Know-JS) - Kyle Simpson
1605 |
1606 | **博客**
1607 |
1608 | - [DailyJS](http://dailyjs.com/)
1609 | - [JavaScript Weekly](http://javascriptweekly.com/)
1610 | - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
1611 | - [Bocoup Weblog](http://weblog.bocoup.com/)
1612 | - [Adequately Good](http://www.adequatelygood.com/)
1613 | - [NCZOnline](http://www.nczonline.net/)
1614 | - [Perfection Kills](http://perfectionkills.com/)
1615 | - [Ben Alman](http://benalman.com/)
1616 | - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
1617 | - [Dustin Diaz](http://dustindiaz.com/)
1618 | - [nettuts](http://net.tutsplus.com/?s=javascript)
1619 |
1620 | **播客**
1621 |
1622 | - [JavaScript Jabber](http://devchat.tv/js-jabber/)
1623 |
1624 |
1625 | **[⬆ 回到顶部](#table-of-contents)**
1626 |
1627 | ## 谁在使用
1628 |
1629 | 这是一个使用本风格指南的组织列表。给我们发 pull request 或开一个 issue 让我们将你增加到列表上。
1630 |
1631 | - **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
1632 | - **Adult Swim**: [adult-swim/javascript](https://github.com/adult-swim/javascript)
1633 | - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
1634 | - **Apartmint**: [apartmint/javascript](https://github.com/apartmint/javascript)
1635 | - **Avalara**: [avalara/javascript](https://github.com/avalara/javascript)
1636 | - **Billabong**: [billabong/javascript](https://github.com/billabong/javascript)
1637 | - **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
1638 | - **DailyMotion**: [dailymotion/javascript](https://github.com/dailymotion/javascript)
1639 | - **Digitpaint** [digitpaint/javascript](https://github.com/digitpaint/javascript)
1640 | - **Evernote**: [evernote/javascript-style-guide](https://github.com/evernote/javascript-style-guide)
1641 | - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
1642 | - **Flexberry**: [Flexberry/javascript-style-guide](https://github.com/Flexberry/javascript-style-guide)
1643 | - **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
1644 | - **General Electric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
1645 | - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
1646 | - **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
1647 | - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
1648 | - **InfoJobs**: [InfoJobs/JavaScript-Style-Guide](https://github.com/InfoJobs/JavaScript-Style-Guide)
1649 | - **Intent Media**: [intentmedia/javascript](https://github.com/intentmedia/javascript)
1650 | - **Jam3**: [Jam3/Javascript-Code-Conventions](https://github.com/Jam3/Javascript-Code-Conventions)
1651 | - **JSSolutions**: [JSSolutions/javascript](https://github.com/JSSolutions/javascript)
1652 | - **Kinetica Solutions**: [kinetica/javascript](https://github.com/kinetica/javascript)
1653 | - **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
1654 | - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
1655 | - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
1656 | - **Money Advice Service**: [moneyadviceservice/javascript](https://github.com/moneyadviceservice/javascript)
1657 | - **Muber**: [muber/javascript](https://github.com/muber/javascript)
1658 | - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
1659 | - **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
1660 | - **Nimbl3**: [nimbl3/javascript](https://github.com/nimbl3/javascript)
1661 | - **Nordic Venture Family**: [CodeDistillery/javascript](https://github.com/CodeDistillery/javascript)
1662 | - **Orion Health**: [orionhealth/javascript](https://github.com/orionhealth/javascript)
1663 | - **Peerby**: [Peerby/javascript](https://github.com/Peerby/javascript)
1664 | - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
1665 | - **reddit**: [reddit/styleguide/javascript](https://github.com/reddit/styleguide/tree/master/javascript)
1666 | - **REI**: [reidev/js-style-guide](https://github.com/reidev/js-style-guide)
1667 | - **Ripple**: [ripple/javascript-style-guide](https://github.com/ripple/javascript-style-guide)
1668 | - **SeekingAlpha**: [seekingalpha/javascript-style-guide](https://github.com/seekingalpha/javascript-style-guide)
1669 | - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
1670 | - **StudentSphere**: [studentsphere/javascript](https://github.com/studentsphere/javascript)
1671 | - **Super**: [SuperJobs/javascript](https://github.com/SuperJobs/javascript)
1672 | - **SysGarage**: [sysgarage/javascript-style-guide](https://github.com/sysgarage/javascript-style-guide)
1673 | - **Target**: [target/javascript](https://github.com/target/javascript)
1674 | - **TheLadders**: [TheLadders/javascript](https://github.com/TheLadders/javascript)
1675 | - **T4R Technology**: [T4R-Technology/javascript](https://github.com/T4R-Technology/javascript)
1676 | - **VoxFeed**: [VoxFeed/javascript-style-guide](https://github.com/VoxFeed/javascript-style-guide)
1677 | - **Weggo**: [Weggo/javascript](https://github.com/Weggo/javascript)
1678 | - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
1679 | - **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)
1680 |
1681 | ## 翻译
1682 |
1683 | 这份风格指南也提供了其它语言的版本:
1684 |
1685 | -  **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
1686 | -  **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript)
1687 | -  **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide)
1688 | -  **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript)
1689 | -  **Chinese(Simplified)**: [sivan/javascript](https://github.com/sivan/javascript)
1690 | -  **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
1691 | -  **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
1692 | -  **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide)
1693 | -  **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
1694 | -  **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
1695 | -  **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript)
1696 | -  **Russian**: [uprock/javascript](https://github.com/uprock/javascript)
1697 | -  **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
1698 | -  **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide)
1699 |
1700 | ## JavaScript 风格指南说明
1701 |
1702 | - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)
1703 |
1704 | ## 与我们讨论 JavaScript
1705 |
1706 | - Find us on [gitter](https://gitter.im/airbnb/javascript).
1707 |
1708 | ## 贡献者
1709 |
1710 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
1711 |
1712 |
1713 | ## 许可
1714 |
1715 | (The MIT License)
1716 |
1717 | Copyright (c) 2014 Airbnb
1718 |
1719 | Permission is hereby granted, free of charge, to any person obtaining
1720 | a copy of this software and associated documentation files (the
1721 | 'Software'), to deal in the Software without restriction, including
1722 | without limitation the rights to use, copy, modify, merge, publish,
1723 | distribute, sublicense, and/or sell copies of the Software, and to
1724 | permit persons to whom the Software is furnished to do so, subject to
1725 | the following conditions:
1726 |
1727 | The above copyright notice and this permission notice shall be
1728 | included in all copies or substantial portions of the Software.
1729 |
1730 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
1731 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1732 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1733 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1734 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1735 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1736 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1737 |
1738 | **[⬆ 回到顶部](#table-of-contents)**
1739 |
1740 | # };
1741 |
--------------------------------------------------------------------------------