JavaScript Style Guide
References
2.1 所有的赋值都用 const
,避免使用 var
。
2.2 如果变量一定需要重新赋值,使用 let
而非 var
。
2.3 注意 let
和 const
都是块级作用域,而 var
是函数级作用域。
Object
3.1 使用字面量语法创建对象。
3.2 Use computed property names when creating objects with dynamic property names.
1 |
|
3.3 对象方法使用简写
1 |
|
3.4 对象属性使用简写
1 |
|
3.5 将简写的对象属性放在对象声明的前面。
1 |
|
3.6 只有当属性名作为标识符非法时,才使用引号包裹。
1 |
|
3.7 不要直接调用 Object.prototype
上的方法,如 hasOwnProperty
、propertyIsEnumerable
和 isPrototypeOf
。
Why? These methods may be shadowed by properties on the object in question - consider { hasOwnProperty: false } - or, the object may be a null object (Object.create(null)).
1 |
|
3.8 对象浅拷贝时,更推荐使用对象扩展语法而不是 Object.assign
。使用对象的 rest 解构运算符获取一个省略了某些属性的新对象。
1 |
|
Arrays
4.1 用字面量语法创建数组
4.2 用 Array#push
代替直接向数组中添加一个值。
4.3 使用数组扩展运算符 ...
(浅)拷贝数组。
1 |
|
4.4 使用 ...
运算符而不是 Array.from
来将一个可迭代的对象转换为数组。
1 |
|
4.5 使用 Array.from
将一个类数组对象转换为一个数组。
1 |
|
4.6 使用 Array.from
而不是 ...
运算符去做 map 迭代。因为这样可以避免产生中间数组。
1 |
|
4.7 在数组方法的回调函数中使用 return 语句。如果函数体由一条返回一个表达式的语句组成,并且这个表达式没有副作用,这个时候可以忽略 return ,详见 8.2。
1 |
|
4.8 如果一个数组有多行,在数组的 [
后和 ]
前断行。
1 |
|
Destructuring
5.1 使用对象解构来访问和使用一个对象的多个属性。
Why? Destructuring saves you from creating temporary references for those properties, and from repetitive access of the object. Repeating object access creates more repetitive code, requires more reading, and creates more opportunities for mistakes. Destructuring objects also provides a single site of definition of the object structure that is used in the block, rather than requiring reading the entire block to determine what is used.
1 |
|
5.2 使用数组解构
1 |
|
5.3 需要多个返回值时使用对象解构而不是数组解构。
1 |
|
Strings
6.1 字符串应使用单引号 ''
。
6.2 超过 100 个字符的字符串不应该连接成多行。
Why? Broken strings are painful to work with and make code less searchable.
1 |
|
6.3 当需要动态生成字符串时,使用模板字符串而不是字符串拼接。
1 |
|
6.4 永远不要在字符串上使用 eval()
,该方法有太多漏洞。
6.5 不要无故的在字符串中转义字符。
Functions
7.1 使用命名函数表达式而不是函数声明
使用函数声明会发生声明提前;使用匿名函数会导致错误难以追踪。
1 |
|
7.2 把立即执行函数表达式(IIFE)包裹在圆括号中。
1 |
|
7.3 不要在非函数块(if
, while
, etc)内声明函数,而应该将函数分配给一个变量。
1 |
|
7.4 函数声明不是一条语句。
7.5 参数名不要使用 arguments
。这将会使得它的优先级高于每个函数作用域自带的 arguments
对象。
7.6 不要使用 arguments
,用收集参数语法 ...
代替。
Why? … is explicit about which arguments you want pulled. Plus, rest arguments are a real Array, and not merely Array-like like arguments.
1 |
|
7.7 用默认参数语法而不是在函数里对参数重新赋值。
1 |
|
7.8 避免默认参数的副作用
看得出写这代码的人一心想的都是“哎,我就是玩!”
1 |
|
7.9 总是把默认参数放在最后。
7.10 永远不要使用函数构造器创建函数
7.11 函数定义部分要有空格。
1 |
|
7.12 不要修改参数或对参数重新赋值
1 |
|
7.13 尽量使用扩展运算符 ...
调用多参数的函数。
1 |
|
7.14 调用或者声明一个包含多个参数的函数,应该像这个指南里的代码一样缩进——即每行只包含一个参数,以逗号结尾。
1 |
|
Arrow Functions
8.1 当你必须使用一个匿名函数时,使用箭头函数。
Why? It creates a version of the function that executes in the context of this, which is usually what you want, and is a more concise syntax.
Why not? If you have a fairly complicated function, you might move that logic out into its own named function expression.
1 |
|
8.2 如果函数体由一条没有副作用的表达式语句构成,可以删除大括号,此时隐式 return 。否则,保留大括号并显式使用 return 语句。
1 |
|
8.3 如果表达式跨越多行,为了更好的可读性可以将它包裹在圆括号中。
1 |
|
8.4 为了清晰和一致性,总是将参数包裹在圆括号中。
8.5 Enforce the location of arrow function bodies with implicit returns.
1 |
|
Classes & Constructors
9.1 总是使用 class
。避免直接操纵 prototype
1 |
|
9.2 使用 extends
实现继承。
1 |
|
9.3 方法可以返回 this
来帮助实现链式调用。
1 |
|
9.4 自己实现 toString()
方法是可以的,但需要保证它可以正常工作并且没有副作用。
1 |
|
9.5 如果没有指定任何构造器,则类有一个默认构造器。
1 |
|
9.6 避免重复定义类成员
Why? Duplicate class member declarations will silently prefer the last one - having duplicates is almost certainly a bug.
1 |
|
9.7 除非外部库或框架需要使用特定的非静态方法,否则类方法应该使用 this
或被定义为静态方法。实例方法表明了它应该根据实例的属性有不同的行为。
1 |
|
Modules
10.1 总是使用 (import
/ export
) 模块而不是非标准的模块系统。你可以随时转到你更喜欢的模块系统。
1 |
|
10.2 不用使用通配符导入。
1 |
|
10.3 不要从 import
中直接 export
。
10.4 一个路径只导入一次。
1 |
|
10.5 不要导出可变的绑定。
1 |
|
10.6 在一个单一导出模块中,用 export default
更好。
1 |
|
10.7 把 import
语句放在所有其他语句之前。
10.8 多行 import
应该缩进。
1 |
|
10.9 在 import
语句中不允许 Webpack loader 语法。
1 |
|
10.10 导入 JavaScript 文件时不要包含扩展名。
Iterators and Generators
11.1 不要使用迭代器。使用 JavaScript 高阶函数代替 for-in
或 for-of
循环。
1 |
|
11.2 现在暂时不要使用生成器。
11.3 如果你一定要使用生成器,请确保它们的函数签名空格得当。
Why? function and * are part of the same conceptual keyword - * is not a modifier for function, function* is a unique construct, different from function.
1 |
|
Properties
12.1 访问属性时使用点 .
语法。
1 |
|
12.2 当使用变量获取属性时用 []
。
12.3 做幂运算时使用幂运算符 **
。
1 |
|
Variables
13.1 使用 const
或 let
每次仅声明一个变量/常量。
1 |
|
13.2 把 const
声明的常量 和 let
声明的变量分别放在一起。
1 |
|
13.3 不要链式声明变量
Why? Chaining variable assignments creates implicit global variables.
1 |
|
13.4 避免使用一元自增自减运算符(++
, --
)。
13.5 赋值时避免在 =
前/后换行。如果你的赋值语句超过 max-len
,那就用圆括号把这个值包起来。
1 |
|
Hoisting
14.1 var declarations get hoisted to the top of their closest enclosing function scope, their assignment does not. const and let declarations are blessed with a new concept called Temporal Dead Zones (TDZ). It’s important to know why typeof is no longer safe.
Comparison Operators & Equality
15.1 使用 ===
和 !==
而不是 ==
和 !=
。
15.2 布尔值要用缩写,但字符串和数字要明确使用比较操作符。
1 |
|
15.3 在 case
和 default
子句里用大括号创建一块包含词法声明的区域。
1 |
|
15.4 三元表达式不应该嵌套,而且一般是单行表达式。
15.5 避免不必要的三元表达式
1 |
|
Blocks
16.1 对所有多行代码块使用大括号。
1 |
|
Control Statements
17.1 Don’t use selection operators in place of control statements.
1 |
|
Comments
18.1 Use /** ... */
for multiline comments.
18.2 Use //
for single line comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment unless it’s on the first line of a block.
1 |
|
18.3 Start all comments with a space to make it easier to read.
18.4 Use //
FIXME: to annotate problems.
1 |
|
18.5 Use //
TODO: to annotate solutions to problems.
1 |
|
Whitespace
19.1 Use soft tabs (space character) set to 2 spaces.
19.2 {
前放置一个空格。
19.3 Place 1 space before the opening parenthesis in control statements (if
, while
etc.). Place no space between the argument list and the function name in function calls and declarations.
1 |
|
19.4 用空格隔开运算符。
19.5 文件结尾空一行。
19.6 Use indentation when making long method chains (more than 2 method chains). Use a leading dot, which emphasizes that the line is a method call, not a new statement.
1 |
|
19.7 Leave a blank line after blocks and before the next statement.
19.8 Do not pad your blocks with blank lines.
1 |
|
19.9 Do not use multiple blank lines to pad your code.
19.10 圆括号里侧不要加空格。
19.11 方括号里侧不要加空格。
19.12 花括号里侧要加空格。
19.13 Avoid having lines of code that are longer than 100 characters (including whitespace). Note: per above, long strings are exempt from this rule, and should not be broken up.
19.14 Avoid spaces before commas and require a space after commas.
19.15 Enforce spacing between keys and values in object literal properties.
1 |
|
19.16 行末不要有空格
19.17 文件开始处不要出现空行
Commas
20.1 不要前置逗号
1 |
|
20.2 额外结尾逗号
1 |
|
Semicolons
21.1 别忘分号
Why? When JavaScript encounters a line break without a semicolon, it uses a set of rules called Automatic Semicolon Insertion to determine whether it should regard that line break as the end of a statement, and (as the name implies) place a semicolon into your code before the line break if it thinks so. ASI contains a few eccentric behaviors, though, and your code will break if JavaScript misinterprets your line break. These rules will become more complicated as new features become a part of JavaScript. Explicitly terminating your statements and configuring your linter to catch missing semicolons will help prevent you from encountering issues.
Type Casting & Coercion
22.1 在语句开始处执行强制类型转换。
22.2 Strings
1 |
|
22.3 Numbers: 使用 Number
做类型转换,使用 parseInt
转换字符串时应总是带上基数。
1 |
|
22.4 If for whatever reason you are doing something wild and parseInt is your bottleneck and need to use Bitshift for performance reasons, leave a comment explaining why and what you’re doing.
1 |
|
22.5 Note: Be careful when using bitshift operations. Numbers are represented as 64-bit values, but bitshift operations always return a 32-bit integer (source). Bitshift can lead to unexpected behavior for integer values larger than 32 bits.
22.6 布尔值
1 |
|
Name Conventions
23.1 避免用一个字母命名
23.2 Use camelCase when naming objects, functions, and instances.
23.3 Use PascalCase only when naming constructors or classes.
23.4 命名时不要用前置或后置下划线
23.5 不要保存 this
引用。使用箭头函数或函数绑定
1 |
|
23.6 基本文件名应能精确匹配它的默认导出的名字。
1 |
|
23.7 当你 export-default 一个函数时,函数名使用 camelCase ,文件名需要和函数名一致
23.8 当你 export 一个 结构体/类/单例/函数库/对象 时用 PascalCase。
1 |
|
23.9 简写和缩写应全部大写或小写。
1 |
|
23.10 你可以用全大写字母设置常量,它需要满足下列三个条件:
- 它是导出变量
- 由
const
定义 - 这个变量是可信的,它和它的子属性都是不能被改变的
1 |
|
Accessors
24.1 不需要使用属性的访问器函数
24.2 不要使用 JavaScript 的 getters/setters 。相反,你可以用 getVal()
和 setVal('hello')
去创建你自己的访问器函数。
1 |
|
24.3 如果 属性/方法 是 boolean
,使用 isVal()
或 hasVal()
。
1 |
|
24.4 创建 get()
和 set()
函数是可以的,但是要一起用。
Events
25.1 When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass an object literal (also known as a “hash”) instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event.
jQuery
26.1 为 jQuery 对象变量附上前缀 $
。
1 |
|
26.2 缓存 jQuery 查询。
1 |
|
26.3 DOM 查询使用 $('.sidebar ul')
或 $('.sidebar > ul')
。
26.4 Use find with scoped jQuery object queries.
1 |
|
ECMAScript 5 Compatibility
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 。
Standard Library
29.1 使用 Number.isNaN
代替全局的 isNaN
。
29.2 使用 Number.isFinite
代替全局的 isFinite
。
Testing
30.1 No, but seriously:
- Whichever testing framework you use, you should be writing tests!
- 尽量去写很多小而美的纯函数(pure functions),从而减少突变的发生。
- 小心 stub 和 mock —— 它们会让你的测试变得脆弱。
- 100% test coverage is a good goal to strive for, even if it’s not always practical to reach it.
- 每当你修复一个 bug ,都要写一个回归测试。在没有回归测试的情况下修复的 bug 几乎肯定会在将来再次出现。
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…
Resources
Learning ES6+
Read This
Tools
- Code Style Linters
- Neutrino Preset - @neutrinojs/airbnb
Other Style Guides
- Google JavaScript Style Guide
- Google JavaScript Style Guide (Old)
- jQuery Core Style Guidelines
- Principles of Writing Consistent, Idiomatic JavaScript
- StandardJS
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
- nettuts
Podcasts(播客)
In the Wild
This is a list of organizations that are using this style guide.
- 123erfasst: 123erfasst/javascript
- 4Catalyzer: 4Catalyzer/javascript
- Aan Zee: AanZee/javascript
- Airbnb: airbnb/javascript
- AloPeyk: AloPeyk
- AltSchool: AltSchool/javascript
- Apartmint: apartmint/javascript
- Ascribe: ascribe/javascript
- Avant: avantcredit/javascript
- Axept: axept/javascript
- Billabong: billabong/javascript
- Bisk: bisk
- Bonhomme: bonhommeparis/javascript
- Brainshark: brainshark/javascript
- CaseNine: CaseNine/javascript
- Cerner: Cerner
- Chartboost: ChartBoost/javascript-style-guide
- Coeur d’Alene Tribe: www.cdatribe-nsn.gov
- 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
- 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
- Happeo: happeo/javascript
- Honey: honeyscience/javascript
- How About We: howaboutwe/javascript
- HubSpot: HubSpot/javascript
- Hyper: hyperoslo/javascript-playbook
- InterCity Group: intercitygroup/javascript-style-guide
- Jam3: Jam3/Javascript-Code-Conventions
- 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
- Muber: muber
- National Geographic: natgeo
- NullDev: NullDevCo/JavaScript-Styleguide
- 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
- 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
- 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
- Terra: terra
- TheLadders: TheLadders/javascript
- The Nerdery: thenerdery/javascript-standards
- Tomify: tomprats
- Traitify: traitify/eslint-config-traitify
- T4R Technology: T4R-Technology/javascript
- UrbanSim: urbansim
- VoxFeed: VoxFeed/javascript-style-guide
- WeBox Studio: weboxstudio/javascript
- Weggo: Weggo/javascript
- Zillow: zillow/javascript
- ZocDoc: ZocDoc/javascript