https://github.com/airbnb/javascript#translation
目录
- Semicolons
- Type Casting & Coercion
- Naming Conventions
- Accessors
- Events
- jQuery
- ECMAScript 5 Compatibility
- ECMAScript 6+ (ES 2015+) Styles
- Standard Library
- Testing
- Performance
- Resources
- In the Wild
- Translation
- The JavaScript Style Guide Guide
- Chat With Us About JavaScript
- Contributors
- License
- 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 你可以用全大写字母设置静态变量,他需要满足三个条件。
- 导出变量
- 是
const
定义的, 保证不能被改变 - 这个变量是可信的,他的子属性都是不能被改变的
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特性的链接
- 箭头函数——Arrow Functions
- 类——Classes
- 对象缩写——Object Shorthand
- 对象简写——Object Concise
- 对象计算属性——Object Computed Properties
- 模板字符串——Template Strings
- 解构赋值——Destructuring
- 默认参数——Default Parameters
- Rest
- Array Spreads
- Let and Const
- 幂操作符——Exponentiation Operator
- 迭代器和生成器——Iterators and Generators
- 模块——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 首选
mocha
。tape
偶尔被用来测试一些小的,独立的模块。 - 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()
, andfilter()
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.