A mostly reasonable approach to JavaScript
一个最讲道理的JavaScript方法论
Modules 模块
[10.1] Always use modules (
import
/export
) over a non-standard module system. You can always transpile to your preferred module system.
在非标准模块系统里总是使用模块 (import
/export
) 。你可以总是使用你喜欢的反编译系统。Why? Modules are the future, let’s start using the future now.
为什么?模块面向未来,让我们开始使用未来的工具吧。1
2
3
4
5
6
7
8
9
10
11// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;[10.2] Do not use wildcard imports.
不要使用通配符引入Why? This makes sure you have a single default export.
为什么? 这个可以保证你有单个默认的输出。1
2
3
4
5// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';[10.3] And do not export directly from an import.
不要导入的时候直接导出。Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
为什么?尽管一行很简洁,但是有一个清晰的导入方式和一个清晰的导出让它们更一致。1
2
3
4
5
6
7
8// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;[10.4] Only import from a path in one place.
eslint:no-duplicate-imports
一个路径只在一个地方引入。Why? Having multiple lines that import from the same path can make code harder to maintain.
为什么?有多行的引入可能导致代码难以维护。1
2
3
4
5
6
7
8
9
10
11
12
13// bad
import foo from 'foo';
// … some other imports … //
import { named1, named2 } from 'foo';
// good
import foo, { named1, named2 } from 'foo';
// good
import foo, {
named1,
named2,
} from 'foo';[10.5] Do not export mutable bindings.
eslint:import/no-mutable-exports
可变值不要导出。Why? Mutation should be avoided in general, but in particular when exporting mutable bindings. While this technique may be needed for some special cases, in general, only constant references should be exported.
为什么?变化一般情况下都应该被避免,尤其是导出可变的绑定值。尽管某些特殊情况需要可变绑定这个技术,但是一般情况下只有不可变引用可以导出。1
2
3
4
5
6
7// bad
let foo = 3;
export { foo };
// good
const foo = 3;
export { foo };[10.6] In modules with a single export, prefer default export over named export.
eslint:import/prefer-default-export
模块内有一个单独的导出,通过名字导出更好。1
2
3
4
5// bad
export function foo() {}
// good
export default function foo() {}[10.7] Put all
import
s above non-import statements.
eslint:import/first
把所有的 import 放在非 import 语句之前。Why? Since
import
s are hoisted, keeping them all at the top prevents surprising behavior.
为什么?尽管import 会变量提升,但是保持他们在头部可以防止奇怪的行为。1
2
3
4
5
6
7
8
9
10
11// bad
import foo from 'foo';
foo.init();
import bar from 'bar';
// good
import foo from 'foo';
import bar from 'bar';
foo.init();[10.8] Multiline imports should be indented just like multiline array and object literals.
多行引入应该缩进成多行数组和对象的语法一样。Why? The curly braces follow the same indentation rules as every other curly brace block in the style guide, as do the trailing commas.
为什么?这个花括号遵守和其他所有花括号的语法规则一样的缩进规则,也同样应该留下末尾的逗号。1
2
3
4
5
6
7
8
9
10
11// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// good
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';[10.9] Disallow Webpack loader syntax in module import statements.
eslint:import/no-webpack-loader-syntax
模块导入语句不允许 webpack loader 语法。Why? Since using Webpack syntax in the imports couples the code to a module bundler. Prefer using the loader syntax in
webpack.config.js
.
为什么? 使用 webpack 的语法在导入语句让模块 bundler 的代码加倍了。更推荐在在webpack.config.js
里面使用 loader 语法。1
2
3
4
5
6
7// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';
Iterators and Generators 迭代器&生成器
[11.1] Don’t use iterators. Prefer JavaScript’s higher-order functions instead of loops like
for-in
orfor-of
. eslint:no-iterator
no-restricted-syntax
别用迭代器。推荐 JS 更高阶的函数而不是循环,如for-in
或for-of
。Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.
为什么? 这样强制执行不可变原则。处理返回值的纯函数比推断副作用要容易。Use
map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ … to iterate over arrays, andObject.keys()
/Object.values()
/Object.entries()
to produce arrays so you can iterate over objects.
用map()
/every()
/filter()
/find()
/findIndex()
/reduce()
/some()
/ … 来迭代数组,用Object.keys()
/Object.values()
/Object.entries()
来生成用来迭代对象的数组1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34const numbers = [1, 2, 3, 4, 5];
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach((num) => {
sum += num;
});
sum === 15;
// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
increasedByOne.push(numbers[i] + 1);
}
// good
const increasedByOne = [];
numbers.forEach((num) => {
increasedByOne.push(num + 1);
});
// best (keeping it functional)
const increasedByOne = numbers.map(num => num + 1);[11.2] Don’t use generators for now.
现在别用生成器。Why? They don’t transpile well to ES5.
为什么?他们现在很难被编译成 ES5。11.3 If you must use generators, or if you disregard our advice, make sure their function signature is spaced properly. eslint:
generator-star-spacing
如果你非要用生成器,或者你无视我们的建议,确保他们的函数签名是空格使用恰当。Why?
function
and*
are part of the same conceptual keyword -*
is not a modifier forfunction
,function*
is a unique construct, different fromfunction
.
为什么?function
和*
是概念上关键词的一部分,*
不是一个队function
的修改者,function*
是一个和function
不同的特殊构造器。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53// bad
function * foo() {
// ...
}
// bad
const bar = function * () {
// ...
};
// bad
const baz = function *() {
// ...
};
// bad
const quux = function*() {
// ...
};
// bad
function*foo() {
// ...
}
// bad
function *foo() {
// ...
}
// very bad
function
*
foo() {
// ...
}
// very bad
const wat = function
*
() {
// ...
};
// good
function* foo() {
// ...
}
// good
const foo = function* () {
// ...
};
Properties 属性
[12.1] Use dot notation when accessing properties. eslint:
dot-notation
jscs:requireDotNotation
存取属性使用点符号。1
2
3
4
5
6
7
8
9
10const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;[12.2] Use bracket notation
[]
when accessing properties with a variable.
存取变量属性的时候使用方括号符号。1
2
3
4
5
6
7
8
9
10const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');[12.3] Use exponentiation operator
**
when calculating exponentiations. eslint:no-restricted-properties
.
使用乘方符号当需要计算幂次方的时候。1
2
3
4
5// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
Variables 变量
[13.1] Always use
const
orlet
to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that. eslint:no-undef
prefer-const
总是使用 const 或者 let 来声明变量。不这么做会产生全局变量。我们想避免污染全局命名空间。地球超人那样警告了我们。1
2
3
4
5// bad
superPower = new SuperPower();
// good
const superPower = new SuperPower();[13.2] Use one
const
orlet
declaration per variable. eslint:one-var
jscs:disallowMultipleVarDecl
每个变量单独使用声明关键词。Why? It’s easier to add new variable declarations this way, and you never have to worry about swapping out a
;
for a,
or introducing punctuation-only diffs. You can also step through each declaration with the debugger, instead of jumping through all of them at once.
为什么?这样更容易加一个新的变量声明,你不需要担心交换分号、逗号或者其他符号之类的问题。你还可以调试的时候步进调试而不是一次性跳过所有。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// bad
const items = getItems(),
goSportsTeam = true,
dragonball = 'z';
// bad
// (compare to above, and try to spot the mistake)
const items = getItems(),
goSportsTeam = true;
dragonball = 'z';
// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';[13.3]Group all your
const
s and then group all yourlet
s.
const 和 let 要进行分组。Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
为什么?当你需要给一个依赖先前变量的变量赋值的时候,这是很有用的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// bad
let i, len, dragonball,
items = getItems(),
goSportsTeam = true;
// bad
let i;
const items = getItems();
let dragonball;
const goSportsTeam = true;
let len;
// good
const goSportsTeam = true;
const items = getItems();
let dragonball;
let i;
let length;[13.4] Assign variables where you need them, but place them in a reasonable place.
在你需要的地方给变量赋值,但是把他们放在符合逻辑的地方。Why?
let
andconst
are block scoped and not function scoped.
为什么?let
andconst
是块作用域而不是函数作用域。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// bad - unnecessary function call
function checkName(hasName) {
const name = getName();
if (hasName === 'test') {
return false;
}
if (name === 'test') {
this.setName('');
return false;
}
return name;
}
// good
function checkName(hasName) {
if (hasName === 'test') {
return false;
}
const name = getName();
if (name === 'test') {
this.setName('');
return false;
}
return name;
}[13.5] Don’t chain variable assignments.
不要链式赋值。Why? Chaining variable assignments creates implicit global variables.
为什么?链式赋值会创造隐式全局变量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// bad
(function example() {
// JavaScript interprets this as
// let a = ( b = ( c = 1 ) );
// The let keyword only applies to variable a; variables b and c become
// global variables.
let a = b = c = 1;
}());
console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1
// good
(function example() {
let a = 1;
let b = a;
let c = a;
}());
console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError
// the same applies for `const`[13.6] Avoid using unary increments and decrements (++, –). eslint
no-plusplus
避免使用单目增减运算符。Why? Per the eslint documentation, unary increment and decrement statements are subject to automatic semicolon insertion and can cause silent errors with incrementing or decrementing values within an application. It is also more expressive to mutate your values with statements like
num += 1
instead ofnum++
ornum ++
. Disallowing unary increment and decrement statements also prevents you from pre-incrementing/pre-decrementing values unintentionally which can also cause unexpected behavior in your programs.
为什么?任何一个 eslint 的文档,单目运算符会自动添加分号,可以造成隐式错误。使用num += 1
这种改变变量值的语句更有表现力。不允许单目运算符还能防止预期之外的预增值或者预减值,这科恩给你造成预期之外的结果。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// bad
const array = [1, 2, 3];
let num = 1;
num++;
--num;
let sum = 0;
let truthyCount = 0;
for (let i = 0; i < array.length; i++) {
let value = array[i];
sum += value;
if (value) {
truthyCount++;
}
}
// good
const array = [1, 2, 3];
let num = 1;
num += 1;
num -= 1;
const sum = array.reduce((a, b) => a + b, 0);
const truthyCount = array.filter(Boolean).length;
Hoisting 变量提升
[14.1]
var
declarations get hoisted to the top of their scope, their assignment does not.const
andlet
declarations are blessed with a new concept called Temporal Dead Zones (TDZ). It’s important to know why typeof is no longer safe.
var 的声明会被提升到作用域的头部,但是赋值不会。const 和 let 声明受益于一个新的概念TDZ。了解一下为什么 typeof 是不安全的很重要。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// we know this wouldn’t work (assuming there
// is no notDefined global variable)
function example() {
console.log(notDefined); // => throws a ReferenceError
}
// creating a variable declaration after you
// reference the variable will work due to
// variable hoisting. Note: the assignment
// value of `true` is not hoisted.
function example() {
console.log(declaredButNotAssigned); // => undefined
var declaredButNotAssigned = true;
}
// the interpreter is hoisting the variable
// declaration to the top of the scope,
// which means our example could be rewritten as:
function example() {
let declaredButNotAssigned;
console.log(declaredButNotAssigned); // => undefined
declaredButNotAssigned = true;
}
// using const and let
function example() {
console.log(declaredButNotAssigned); // => throws a ReferenceError
console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
const declaredButNotAssigned = true;
}[14.2] Anonymous function expressions hoist their variable name, but not the function assignment.
匿名函数表达式提升他们的变量名,但是不提升函数赋值。1
2
3
4
5
6
7
8
9function example() {
console.log(anonymous); // => undefined
anonymous(); // => TypeError anonymous is not a function
var anonymous = function () {
console.log('anonymous function expression');
};
}[14.3] Named function expressions hoist the variable name, not the function name or the function body.
实名函数表达式提升变量名,不提升函数名和函数主体。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
superPower(); // => ReferenceError superPower is not defined
var named = function superPower() {
console.log('Flying');
};
}
// the same is true when the function name
// is the same as the variable name.
function example() {
console.log(named); // => undefined
named(); // => TypeError named is not a function
var named = function named() {
console.log('named');
};
}[14.4] Function declarations hoist their name and the function body.
函数声明提升名字和函数主体1
2
3
4
5
6
7function example() {
superPower(); // => Flying
function superPower() {
console.log('Flying');
}
}For more information refer to JavaScript Scoping & Hoisting by Ben Cherry.
了解更多💩特性上这个网站JavaScript Scoping & Hoisting by Ben Cherry.
Comparison Operators & Equality 比较符号&相等判断
[15.1] Use
===
and!==
over==
and!=
. eslint:eqeqeq
使用三等号三不等,不用双等双不等。[15.2] Conditional statements such as the
if
statement evaluate their expression using coercion with theToBoolean
abstract method and always follow these simple rules:
条件语句比如 if 强制使用 toBoolean 抽象方法来判断值:- Objects evaluate to true
- Undefined evaluates to false
- Null evaluates to false
- Booleans evaluate to the value of the boolean
- Numbers evaluate to false if +0, -0, or NaN, otherwise true
- Strings evaluate to false if an empty string
''
, otherwise true
1
2
3
4if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}[15.3] Use shortcuts for booleans, but explicit comparisons for strings and numbers.
使用布尔值简写,但是严格的比较字符串和数字。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// bad
if (isValid === true) {
// ...
}
// good
if (isValid) {
// ...
}
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
// good
if (collection.length > 0) {
// ...
}[15.4] For more information see Truth Equality and JavaScript by Angus Croll.
更多信息查看这个Truth Equality and JavaScript by Angus Croll.[15.5] Use braces to create blocks in
case
anddefault
clauses that contain lexical declarations (e.g.let
,const
,function
, andclass
). eslint:no-case-declarations
用花括号把包含字符定义的 case or default 子句起来Why? Lexical declarations are visible in the entire
switch
block but only get initialized when assigned, which only happens when itscase
is reached. This causes problems when multiplecase
clauses attempt to define the same thing.
为什么?字符声明对整个 switch 块可见,但是只有在初始化的时候可以复制,只在 case 到达的时候发生,这可能在多个子句定义同样的东西的时候带来问题。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// bad
switch (foo) {
case 1:
let x = 1;
break;
case 2:
const y = 2;
break;
case 3:
function f() {
// ...
}
break;
default:
class C {}
}
// good
switch (foo) {
case 1: {
let x = 1;
break;
}
case 2: {
const y = 2;
break;
}
case 3: {
function f() {
// ...
}
break;
}
case 4:
bar();
break;
default: {
class C {}
}
}[15.6] Ternaries should not be nested and generally be single line expressions. eslint:
no-nested-ternary
三目运算不应该嵌套,一般应该一行一个。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// better
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const maybeNull = value1 > value2 ? 'baz' : null;
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;[15.7] Avoid unneeded ternary statements. eslint:
no-unneeded-ternary
避免不必要的三目运算。1
2
3
4
5
6
7
8
9
10
11// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
//两个感叹号表示某个元素是否存在。 可以理解为强制转 boolean
//还有~~是下取整
const baz = !c;
Blocks 块
[16.1] Use braces with all multi-line blocks.
使用多行的块用花括号包起来。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}[16.2] If you’re using multi-line blocks with
if
andelse
, putelse
on the same line as yourif
block’s closing brace. eslint:brace-style
jscs:disallowNewlineBeforeBlockStatements
如果你使用含 if else 的多行块,把上一个右括号和下一个左括号和关键字放一行。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
Control Statements 控制语句
[17.1] In case your control statement (
if
,while
etc.) gets too long or exceeds the maximum line length, each (grouped) condition could be put into a new line. It’s up to you whether the logical operator should begin or end the line.
万一你的控制语句(如 if else)太长了或者超过了最大单行长度限制,每个条件应该单独放一行。逻辑符号放行首或行尾你可以自己定。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// good
if (
(foo === 123 || bar === "abc") &&
doesItLookGoodWhenItBecomesThatLong() &&
isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
// good
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
Comments 注释
[18.1] Use
/** ... */
for multi-line comments.
使用/** ... */
来做多行注释。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}[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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// also good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}[18.3] Start all comments with a space to make it easier to read. eslint:
spaced-comment
所有的评论先打一个空格,方便阅读。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}[18.4] Prefixing your comments with
FIXME
orTODO
helps other developers quickly understand if you’re pointing out a problem that needs to be revisited, or if you’re suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions areFIXME: -- need to figure this out
orTODO: -- need to implement
.
用FIXME
或TODO
当前缀的评论帮助其他的开发者迅速理解你指出了一个需要重访的问题,或者你推荐一个需要被实现的解决方案。这些不同于普通评论,因为他们可以提出行动要求。功能如:FIXME: -- need to figure this out
orTODO: -- need to implement
.[18.5] Use
// FIXME:
to annotate problems.
使用// FIXME:
来注释问题1
2
3
4
5
6
7
8class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn’t use a global here
total = 0;
}
}[18.6] Use
// TODO:
to annotate solutions to problems.
使用// TODO:
来注释需要解决的问题。1
2
3
4
5
6
7
8class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
Whitespace 空格
[19.1] Use soft tabs (space character) set to 2 spaces. eslint:
indent
jscs:validateIndentation
使用 软TAB/空格 设置两个空格。1
2
3
4
5
6
7
8
9
10
11
12
13
14// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}[19.2] Place 1 space before the leading brace. eslint:
space-before-blocks
jscs:requireSpaceBeforeBlockStatements
花括号前使用一个空格。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// bad
function test(){
console.log('test');
}
// good
function test() {
console.log('test');
}
// bad
dog.set('attr',{
age: '1 year',
breed: 'Bernese Mountain Dog',
});
// good
dog.set('attr', {
age: '1 year',
breed: 'Bernese Mountain Dog',
});[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. eslint:keyword-spacing
jscs:requireSpaceAfterKeywords
控制语句的左圆括号前放一个空格。参数列表之间、函数调用和声明里的函数名不要放空格。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}[19.4] Set off operators with spaces. eslint:
space-infix-ops
jscs:requireSpaceBeforeBinaryOperators
,requireSpaceAfterBinaryOperators
操作符用空格分开。1
2
3
4
5// bad
const x=y+5;
// good
const x = y + 5;[19.5] End files with a single newline character. eslint:
eol-last
文件末尾来一个新行。1
2
3
4// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;1
2
3
4
5// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
↵1
2
3
4// good
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵[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. eslint:
newline-per-chained-call
no-whitespace-before-property
长的方法调用链应该使用缩进。使用一个前导的点,强调这个行是一个方法调用,不是声明。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();
// bad
$('#items').
find('.selected').
highlight().
end().
find('.open').
updateCount();
// good
$('#items')
.find('.selected')
.highlight()
.end()
.find('.open')
.updateCount();
// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
.attr('width', (radius + margin) * 2).append('svg:g')
.attr('transform', `translate(${radius + margin},${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led')
.data(data)
.enter().append('svg:svg')
.classed('led', true)
.attr('width', (radius + margin) * 2)
.append('svg:g')
.attr('transform', `translate(${radius + margin},${radius + margin})`)
.call(tron.led);
// good
const leds = stage.selectAll('.led').data(data);[19.7] Leave a blank line after blocks and before the next statement. jscs:
requirePaddingNewLinesAfterBlocks
块后面应该加一个空行再写其他句子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52// bad
if (foo) {
return bar;
}
return baz;
// good
if (foo) {
return bar;
}
return baz;
// bad
const obj = {
foo() {
},
bar() {
},
};
return obj;
// good
const obj = {
foo() {
},
bar() {
},
};
return obj;
// bad
const arr = [
function foo() {
},
function bar() {
},
];
return arr;
// good
const arr = [
function foo() {
},
function bar() {
},
];
return arr;[19.8] Do not pad your blocks with blank lines. eslint:
padded-blocks
jscs:disallowPaddingNewlinesInBlocks
不要用空行来填补块。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// bad
function bar() {
console.log(foo);
}
// also bad
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(qux);
} else {
console.log(foo);
}[19.9] Do not add spaces inside parentheses. eslint:
space-in-parens
jscs:disallowSpacesInsideParentheses
圆括号内侧不要加空格。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}[19.10] Do not add spaces inside brackets. eslint:
array-bracket-spacing
jscs:disallowSpacesInsideArrayBrackets
方括号内侧不要加空格。1
2
3
4
5
6
7// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);[19.11] Add spaces inside curly braces. eslint:
object-curly-spacing
jscs:requireSpacesInsideObjectBrackets
花括号内侧加空格。1
2
3
4
5// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };[19.12] 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. eslint:
max-len
jscs:maximumLineLength
避免一个行超过100个字符。注意,所有的长字符串都不应该超过这个限制。应该把他们分开。Why? This ensures readability and maintainability.
为什么?这个包装可读性和可维护性。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// bad
const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
// bad
$.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
// good
const foo = jsonData
&& jsonData.foo
&& jsonData.foo.bar
&& jsonData.foo.bar.baz
&& jsonData.foo.bar.baz.quux
&& jsonData.foo.bar.baz.quux.xyzzy;
// good
$.ajax({
method: 'POST',
url: 'https://airbnb.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));