Airbnb JavaScript 风格指南2

https://github.com/airbnb/javascript#translation

目录

  1. Semicolons
  2. Type Casting & Coercion
  3. Naming Conventions
  4. Accessors
  5. Events
  6. jQuery
  7. ECMAScript 5 Compatibility
  8. ECMAScript 6+ (ES 2015+) Styles
  9. Standard Library
  10. Testing
  11. Performance
  12. Resources
  13. In the Wild
  14. Translation
  15. The JavaScript Style Guide Guide
  16. Chat With Us About JavaScript
  17. Contributors
  18. License
  19. Amendments

Semicolons

  • 21.1 Yup. eslint: semi

    Why? 当 JavaScript 遇到没有分号结尾的一行,它会执行自动插入分号 Automatic Semicolon Insertion这一规则来决定行末是否加分号。如果JavaScript在你的断行里错误的插入了分号,就会出现一些古怪的行为。当新的功能加到JavaScript里后, 这些规则会变得更复杂难懂。显示的结束语句,并通过配置代码检查去捕获没有带分号的地方可以帮助你防止这种错误。

    // bad
    (function () {
      const name = 'Skywalker'
      return name
    })()
    
    // good
    (function () {
      const name = 'Skywalker';
      return name;
    }());
    
    // good, 行首加分号,避免文件被连接到一起时立即执行函数被当做变量来执行。
    ;(() => {
      const name = 'Skywalker';
      return name;
    }());
    

    Read more.

⬆ back to top

Type Casting & Coercion


  • 22.1 在语句开始执行强制类型转换。


  • 22.2 Strings: eslint: no-new-wrappers

    // => this.reviewScore = 9;
    
    // bad
    const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"
    
    // bad
    const totalScore = this.reviewScore + ''; // invokes this.reviewScore.valueOf()
    
    // bad
    const totalScore = this.reviewScore.toString(); // 不保证返回string
    
    // good
    const totalScore = String(this.reviewScore);
    


  • 22.3 Numbers: 用 Number 做类型转换,parseInt转换string常需要带上基数。 eslint: radix

    const inputValue = '4';
    
    // bad
    const val = new Number(inputValue);
    
    // bad
    const val = +inputValue;
    
    // bad
    const val = inputValue >> 0;
    
    // bad
    const val = parseInt(inputValue);
    
    // good
    const val = Number(inputValue);
    
    // good
    const val = parseInt(inputValue, 10);
    


  • 22.4 请在注释中解释为什么要用移位运算和你在做什么。无论你做什么狂野的事,比如由于 parseInt 是你的性能瓶颈导致你一定要用移位运算。 请说明这个是因为性能原因,

    // good
    /**
     * parseInt是代码运行慢的原因
     * 用Bitshifting将字符串转成数字使代码运行效率大幅增长
     */
    const val = inputValue >> 0;
    


  • 22.5 注意: 用移位运算要小心. 数字使用64-位表示的,但移位运算常常返回的是32为整形source)。移位运算对大于32位的整数会导致意外行为。Discussion. 最大的32位整数是 2,147,483,647:

    2147483647 >> 0 //=> 2147483647
    2147483648 >> 0 //=> -2147483648
    2147483649 >> 0 //=> -2147483647
    


  • 22.6 布尔:

    const age = 0;
    
    // bad
    const hasAge = new Boolean(age);
    
    // good
    const hasAge = Boolean(age);
    
    // best
    const hasAge = !!age;
    

⬆ back to top

Naming Conventions


  • 23.1 避免用一个字母命名,让你的命名可描述。 eslint: id-length

    // bad
    function q() {
      // ...
    }
    
    // good
    function query() {
      // ...
    }
    


  • 23.2 用小驼峰式命名你的对象、函数、实例。 eslint: camelcase

    // bad
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // good
    const thisIsMyObject = {};
    function thisIsMyFunction() {}
    


  • 23.3 用大驼峰式命名类。 eslint: new-cap

    // bad
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // good
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });
    


  • 23.4 不要用前置或后置下划线。 eslint: no-underscore-dangle

    Why? JavaScript 没有私有属性或私有方法的概念。尽管前置下划线通常的概念上意味着“private”,事实上,这些属性是完全公有的,因此这部分也是你的API的内容。这一概念可能会导致开发者误以为更改这个不会导致崩溃或者不需要测试。 如果你想要什么东西变成“private”,那就不要让它在这里出现。

    // bad
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // good
    this.firstName = 'Panda';
    


  • 23.5 不要保存引用this, 用箭头函数或函数绑定——Function#bind.

    // bad
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }
    
    // bad
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }
    
    // good
    function foo() {
      return () => {
        console.log(this);
      };
    }
    


  • 23.6 export default导出模块A,则这个文件名也叫A.*, import 时候的参数也叫A。 大小写完全一致。

    // file 1 contents
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // file 2 contents
    export default function fortyTwo() { return 42; }
    
    // file 3 contents
    export default function insideDirectory() {}
    
    // in some other file
    // bad
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // bad
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // good
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ supports both insideDirectory.js and insideDirectory/index.js
    


  • 23.7 当你export-default一个函数时,函数名用小驼峰,文件名需要和函数名一致。

    function makeStyleGuide() {
      // ...
    }
    
    export default makeStyleGuide;
    


  • 23.8 当你export一个结构体/类/单例/函数库/对象 时用大驼峰。

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
    


  • 23.9 简称和缩写应该全部大写或全部小写。

    Why? 名字都是给人读的,不是为了适应电脑的算法的。

    // bad
    import SmsContainer from './containers/SmsContainer';
    
    // bad
    const HttpRequests = [
      // ...
    ];
    
    // good
    import SMSContainer from './containers/SMSContainer';
    
    // good
    const HTTPRequests = [
      // ...
    ];
    
    // also good
    const httpRequests = [
      // ...
    ];
    
    // best
    import TextMessageContainer from './containers/TextMessageContainer';
    
    // best
    const requests = [
      // ...
    ];
    


  • 23.10 你可以用全大写字母设置静态变量,他需要满足三个条件。

    1. 导出变量
    2. const 定义的, 保证不能被改变
    3. 这个变量是可信的,他的子属性都是不能被改变的

    Why? 这是一个附加工具,帮助开发者去辨识一个变量是不是不可变的。
    - 对于所有的 const 变量呢? —— 这个是不必要的。大写变量不应该在同一个文件里定义并使用, 它只能用来作为导出变量。 赞同!
    - 那导出的对象呢? —— 大写变量处在export的最高级(e.g. EXPORTED_OBJECT.key) 并且他包含的所有子属性都是不可变的。

    // bad
    const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
    
    // bad
    export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
    
    // bad
    export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
    
    // ---
    
    // 允许但不够语义化
    export const apiKey = 'SOMEKEY';
    
    // 在大多数情况下更好
    export const API_KEY = 'SOMEKEY';
    
    // ---
    
    // bad - 不必要的大写键,没有增加任何语言
    export const MAPPING = {
      KEY: 'value'
    };
    
    // good
    export const MAPPING = {
      key: 'value'
    };
    

⬆ back to top

Accessors


  • 24.1 不需要使用属性的访问器函数。


  • 24.2 不要使用JavaScript的getters/setters,因为他们会产生副作用,并且难以测试、维护和理解。相反的,你可以用 getVal()和setVal('hello')去创造你自己的accessor函数

    // bad
    class Dragon {
      get age() {
        // ...
      }
    
      set age(value) {
        // ...
      }
    }
    
    // good
    class Dragon {
      getAge() {
        // ...
      }
    
      setAge(value) {
        // ...
      }
    }
    


  • 24.3 如果属性/方法是boolean, 用 isVal()hasVal()

    // bad
    if (!dragon.age()) {
      return false;
    }
    
    // good
    if (!dragon.hasAge()) {
      return false;
    }
    


  • 24.4 用get()和set()函数是可以的,但是要一起用

    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }
    
      set(key, val) {
        this[key] = val;
      }
    
      get(key) {
        return this[key];
      }
    }
    

⬆ back to top

Events


  • 25.1 通过哈希而不是原始值向事件装载数据时(不论是DOM事件还是像Backbone事件的很多属性)。 这使得后续的贡献者(程序员)向这个事件装载更多的数据时不用去找或者更新每个处理器。例如:

    // bad
    $(this).trigger('listingUpdated', listing.id);
    
    // ...
    
    $(this).on('listingUpdated', (e, listingID) => {
      // do something with listingID
    });
    

    prefer:

    // good
    $(this).trigger('listingUpdated', { listingID: listing.id });
    
    // ...
    
    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingID
    });
    

⬆ back to top

jQuery


  • 26.1 jQuery对象用$变量表示。

    // bad
    const sidebar = $('.sidebar');
    
    // good
    const $sidebar = $('.sidebar');
    
    // good
    const $sidebarBtn = $('.sidebar-btn');
    


  • 26.2 暂存jQuery查找

    // bad
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...
    
      $('.sidebar').css({
        'background-color': 'pink'
      });
    }
    
    // good
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...
    
      $sidebar.css({
        'background-color': 'pink'
      });
    }
    


  • 26.3 DOM查找用层叠式$('.sidebar ul') 或 父节点 > 子节点 $('.sidebar > ul'). jsPerf


  • 26.4 用jQuery对象查询作用域的find方法查询

    // bad
    $('ul', '.sidebar').hide();
    
    // bad
    $('.sidebar').find('ul').hide();
    
    // good
    $('.sidebar ul').hide();
    
    // good
    $('.sidebar > ul').hide();
    
    // good
    $sidebar.find('ul').hide();
    

⬆ back to top

ES5 兼容性


  • 27.1 参考Kangax的ES5兼容性列表.

⬆ back to top

ECMAScript 6+ (ES 2015+) Styles


  • 28.1 这是收集到的各种ES6特性的链接
  1. 箭头函数——Arrow Functions
  2. 类——Classes
  3. 对象缩写——Object Shorthand
  4. 对象简写——Object Concise
  5. 对象计算属性——Object Computed Properties
  6. 模板字符串——Template Strings
  7. 解构赋值——Destructuring
  8. 默认参数——Default Parameters
  9. Rest
  10. Array Spreads
  11. Let and Const
  12. 幂操作符——Exponentiation Operator
  13. 迭代器和生成器——Iterators and Generators
  14. 模块——Modules


  • 28.2 不要用TC39 proposals, TC39还没有到 stage 3。

    Why? 它还不是最终版, 他可能还有很多变化,或者被撤销。 我们想要用的是 JavaScript, 提议还不是JavaScript。

⬆ back to top

Standard Library

标准库中包含一些功能受损但是由于历史原因遗留的工具类


  • 29.1 用 Number.isNaN 代替全局的 isNaN.
    eslint: no-restricted-globals

    Why? 全局 isNaN 强制把非数字转成数字, 然后对于任何强转后为 NaN 的变量都返回 true
    如果你想用这个功能,就显式的用它。

    // bad
    isNaN('1.2'); // false
    isNaN('1.2.3'); // true
    
    // good
    Number.isNaN('1.2.3'); // false
    Number.isNaN(Number('1.2.3')); // true
    


  • 29.2 用 Number.isFinite 代替 isFinite.
    eslint: no-restricted-globals

    Why? 理由同上,会把一个非数字变量强转成数字,然后做判断。

    // bad
    isFinite('2e3'); // true
    
    // good
    Number.isFinite('2e3'); // false
    Number.isFinite(parseInt('2e3', 10)); // true
    

Testing


  • 30.1 Yup.

    function foo() {
      return true;
    }
    


  • 30.2 No, but seriously:
  • 无论用那个测试框架,你都需要写测试。
  • 尽量去写很多小而美的纯函数,减少突变的发生
  • 小心 stub 和 mock —— 这会让你的测试变得脆弱。
  • 在 Airbnb 首选 mochatape 偶尔被用来测试一些小的,独立的模块。
  • 100%测试覆盖率是我们努力的目标,即便实际上很少达到。
  • 每当你修了一个bug, 都要写一个回归测试。 一个bug修复了,没有回归测试,很可能以后会再次出问题。

⬆ back to top

Performance

  • On Layout & Web Performance
  • String vs Array Concat
  • Try/Catch Cost In a Loop
  • Bang Function
  • jQuery Find vs Context, Selector
  • innerHTML vs textContent for script text
  • Long String Concatenation
  • Are Javascript functions like map(), reduce(), and filter() optimized for traversing arrays?
  • Loading...

⬆ back to top

Resources

Learning ES6

  • Draft ECMA 2015 (ES6) Spec
  • ExploringJS
  • ES6 Compatibility Table
  • Comprehensive Overview of ES6 Features

Read This

  • Standard ECMA-262

Tools

  • Code Style Linters
    • ESlint - Airbnb Style .eslintrc
    • JSHint - Airbnb Style .jshintrc
    • JSCS - Airbnb Style Preset

Other Style Guides

  • Google JavaScript Style Guide
  • jQuery Core Style Guidelines
  • Principles of Writing Consistent, Idiomatic JavaScript

Other Styles

  • Naming this in nested functions - Christian Johansen
  • Conditional Callbacks - Ross Allen
  • Popular JavaScript Coding Conventions on GitHub - JeongHoon Byun
  • Multiple var statements in JavaScript, not superfluous - Ben Alman

Further Reading

  • Understanding JavaScript Closures - Angus Croll
  • Basic JavaScript for the impatient programmer - Dr. Axel Rauschmayer
  • You Might Not Need jQuery - Zack Bloom & Adam Schwartz
  • ES6 Features - Luke Hoban
  • Frontend Guidelines - Benjamin De Cock

Books

  • JavaScript: The Good Parts - Douglas Crockford
  • JavaScript Patterns - Stoyan Stefanov
  • Pro JavaScript Design Patterns - Ross Harmes and Dustin Diaz
  • High Performance Web Sites: Essential Knowledge for Front-End Engineers - Steve Souders
  • Maintainable JavaScript - Nicholas C. Zakas
  • JavaScript Web Applications - Alex MacCaw
  • Pro JavaScript Techniques - John Resig
  • Smashing Node.js: JavaScript Everywhere - Guillermo Rauch
  • Secrets of the JavaScript Ninja - John Resig and Bear Bibeault
  • Human JavaScript - Henrik Joreteg
  • Superhero.js - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
  • JSBooks - Julien Bouquillon
  • Third Party JavaScript - Ben Vinegar and Anton Kovalyov
  • Effective JavaScript: 68 Specific Ways to Harness the Power of JavaScript - David Herman
  • Eloquent JavaScript - Marijn Haverbeke
  • You Don't Know JS: ES6 & Beyond - Kyle Simpson

Blogs

  • JavaScript Weekly
  • JavaScript, JavaScript...
  • Bocoup Weblog
  • Adequately Good
  • NCZOnline
  • Perfection Kills
  • Ben Alman
  • Dmitry Baranovskiy
  • Dustin Diaz
  • nettuts

Podcasts

  • JavaScript Air
  • JavaScript Jabber

⬆ back to top

In the Wild

This is a list of organizations that are using this style guide. Send us a pull request and we'll add you to the list.

  • 123erfasst: 123erfasst/javascript
  • 3blades: 3Blades
  • 4Catalyzer: 4Catalyzer/javascript
  • Aan Zee: AanZee/javascript
  • Adult Swim: adult-swim/javascript
  • Airbnb: airbnb/javascript
  • AltSchool: AltSchool/javascript
  • Apartmint: apartmint/javascript
  • Ascribe: ascribe/javascript
  • Avalara: avalara/javascript
  • Avant: avantcredit/javascript
  • Axept: axept/javascript
  • BashPros: BashPros/javascript
  • Billabong: billabong/javascript
  • Bisk: bisk
  • Bonhomme: bonhommeparis/javascript
  • Brainshark: brainshark/javascript
  • CaseNine: CaseNine/javascript
  • Cerner: Cerner
  • Chartboost: ChartBoost/javascript-style-guide
  • ComparaOnline: comparaonline/javascript
  • Compass Learning: compasslearning/javascript-style-guide
  • DailyMotion: dailymotion/javascript
  • DoSomething: DoSomething/eslint-config
  • Digitpaint digitpaint/javascript
  • Drupal: www.drupal.org
  • Ecosia: ecosia/javascript
  • Evernote: evernote/javascript-style-guide
  • Evolution Gaming: evolution-gaming/javascript
  • EvozonJs: evozonjs/javascript
  • ExactTarget: ExactTarget/javascript
  • Expensify Expensify/Style-Guide
  • Flexberry: Flexberry/javascript-style-guide
  • Gawker Media: gawkermedia
  • General Electric: GeneralElectric/javascript
  • Generation Tux: GenerationTux/javascript
  • GoodData: gooddata/gdc-js-style
  • GreenChef: greenchef/javascript
  • Grooveshark: grooveshark/javascript
  • Grupo-Abraxas: Grupo-Abraxas/javascript
  • Honey: honeyscience/javascript
  • How About We: howaboutwe/javascript
  • Huballin: huballin
  • HubSpot: HubSpot/javascript
  • Hyper: hyperoslo/javascript-playbook
  • InterCity Group: intercitygroup/javascript-style-guide
  • Jam3: Jam3/Javascript-Code-Conventions
  • JeopardyBot: kesne/jeopardy-bot
  • JSSolutions: JSSolutions/javascript
  • Kaplan Komputing: kaplankomputing/javascript
  • KickorStick: kickorstick
  • Kinetica Solutions: kinetica/javascript
  • LEINWAND: LEINWAND/javascript
  • Lonely Planet: lonelyplanet/javascript
  • M2GEN: M2GEN/javascript
  • Mighty Spring: mightyspring/javascript
  • MinnPost: MinnPost/javascript
  • MitocGroup: MitocGroup/javascript
  • ModCloth: modcloth/javascript
  • Money Advice Service: moneyadviceservice/javascript
  • Muber: muber
  • National Geographic: natgeo
  • Nimbl3: nimbl3/javascript
  • Nulogy: nulogy/javascript
  • Orange Hill Development: orangehill/javascript
  • Orion Health: orionhealth/javascript
  • OutBoxSoft: OutBoxSoft/javascript
  • Peerby: Peerby/javascript
  • Pier 1: Pier1/javascript
  • Qotto: Qotto/javascript-style-guide
  • Razorfish: razorfish/javascript-style-guide
  • reddit: reddit/styleguide/javascript
  • React: facebook.github.io/react/contributing/how-to-contribute.html#style-guide
  • REI: reidev/js-style-guide
  • Ripple: ripple/javascript-style-guide
  • Sainsbury’s Supermarkets: jsainsburyplc
  • SeekingAlpha: seekingalpha/javascript-style-guide
  • Shutterfly: shutterfly/javascript
  • Sourcetoad: sourcetoad/javascript
  • Springload: springload
  • StratoDem Analytics: stratodem/javascript
  • SteelKiwi Development: steelkiwi/javascript
  • StudentSphere: studentsphere/javascript
  • SwoopApp: swoopapp/javascript
  • SysGarage: sysgarage/javascript-style-guide
  • Syzygy Warsaw: syzygypl/javascript
  • Target: target/javascript
  • TheLadders: TheLadders/javascript
  • The Nerdery: thenerdery/javascript-standards
  • T4R Technology: T4R-Technology/javascript
  • VoxFeed: VoxFeed/javascript-style-guide
  • WeBox Studio: weboxstudio/javascript
  • Weggo: Weggo/javascript
  • Zillow: zillow/javascript
  • ZocDoc: ZocDoc/javascript

⬆ back to top

Translation

This style guide is also available in other languages:

  • [站外图片上传中...(image-4027c0-1596027990387)] Brazilian Portuguese: armoucar/javascript-style-guide
  • [站外图片上传中...(image-560bf1-1596027990387)] Bulgarian: borislavvv/javascript
  • [站外图片上传中...(image-a3c987-1596027990387)] Catalan: fpmweb/javascript-style-guide
  • [站外图片上传中...(image-6beea5-1596027990387)] Chinese (Simplified): lin-123/javascript
  • [站外图片上传中...(image-50e8e7-1596027990387)] Chinese (Traditional): jigsawye/javascript
  • [站外图片上传中...(image-8a58b3-1596027990387)] French: nmussy/javascript-style-guide
  • [站外图片上传中...(image-cad628-1596027990387)] German: timofurrer/javascript-style-guide
  • [站外图片上传中...(image-fbd0e-1596027990387)] Italian: sinkswim/javascript-style-guide
  • [站外图片上传中...(image-647283-1596027990387)] Japanese: mitsuruog/javascript-style-guide
  • [站外图片上传中...(image-6db992-1596027990387)] Korean: ParkSB/javascript-style-guide
  • [站外图片上传中...(image-442266-1596027990387)] Russian: leonidlebedev/javascript-airbnb
  • [站外图片上传中...(image-9fcce7-1596027990387)] Spanish: paolocarrasco/javascript-style-guide
  • [站外图片上传中...(image-47a04d-1596027990387)] Thai: lvarayut/javascript-style-guide
  • [站外图片上传中...(image-5933b5-1596027990387)] Turkish: eraycetinay/javascript
  • [站外图片上传中...(image-79dc0a-1596027990387)] Ukrainian: ivanzusko/javascript
  • [站外图片上传中...(image-83f9c9-1596027990387)] Vietnam: hngiang/javascript-style-guide

The JavaScript Style Guide Guide

  • Reference

Chat With Us About JavaScript

  • Find us on gitter.

Contributors

  • View Contributors

License

(The MIT License)

Copyright (c) 2012 Airbnb

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

⬆ back to top

Amendments

We encourage you to fork this guide and change the rules to fit your team’s style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.

};

你可能感兴趣的:(Airbnb JavaScript 风格指南2)