├── 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 = ''; 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 | - ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide) 1686 | - ![bg](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Bulgaria.png) **Bulgarian**: [borislavvv/javascript](https://github.com/borislavvv/javascript) 1687 | - ![ca](https://raw.githubusercontent.com/fpmweb/javascript-style-guide/master/img/catala.png) **Catalan**: [fpmweb/javascript-style-guide](https://github.com/fpmweb/javascript-style-guide) 1688 | - ![tw](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Taiwan.png) **Chinese(Traditional)**: [jigsawye/javascript](https://github.com/jigsawye/javascript) 1689 | - ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese(Simplified)**: [sivan/javascript](https://github.com/sivan/javascript) 1690 | - ![fr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/France.png) **French**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide) 1691 | - ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) 1692 | - ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**: [sinkswim/javascript-style-guide](https://github.com/sinkswim/javascript-style-guide) 1693 | - ![jp](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) 1694 | - ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide) 1695 | - ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [mjurczyk/javascript](https://github.com/mjurczyk/javascript) 1696 | - ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**: [uprock/javascript](https://github.com/uprock/javascript) 1697 | - ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide) 1698 | - ![th](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Thailand.png) **Thai**: [lvarayut/javascript-style-guide](https://github.com/lvarayut/javascript-style-guide) 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 | --------------------------------------------------------------------------------