编码风格
- 缩进
强制 使用 4 个空格缩进。eslint: indent
. 统一使用 4个空格缩进,不要使用 2个空格或 tab 缩进:
/* bad */
function foo() {
let name;
}
/* good */
function foo() {
let name;
}
- 分号
强制 使用分号。eslint: semi
. 统一以分号结束语句,可以避免 JS 引擎自动分号插入机制的怪异行为,在语义上也更加明确。
/*
* bad - 导致 Uncaught ReferenceError 报错
*/
const luke = {}
const leia = {}
[luke, leia].forEach((jedi) => {
jedi.father = 'vader'
})
/* good */
const luke = {};
const leia = {};
[luke, leia].forEach((jedi) => {
jedi.father = 'vader';
});
/*
* bad - 导致 Uncaught ReferenceError 报错
*/
const reaction = "No! That's impossible!"
(async function meanwhileOnTheFalcon() {
}())
/* good */
const reaction = "No! That's impossible!";
(async function meanwhileOnTheFalcon() {
}());
/*
* bad - 函数将返回 `undefined` 而不是换行后的值
*/
function foo() {
return
'Result want to be returned'
}
/* good */
function foo() {
return 'Result want to be returned';
}
- 逗号
- 强制对于用逗号分隔的多行结构,不使用行首逗号。
eslint:comma-style
/* bad */
const story = [
once
, upon
, aTime
];
/* good */
const story = [
once,
upon,
aTime,
];
/* bad */
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, superPower: 'computers'
};
/* good */
const hero = {
firstName: 'Ada',
lastName: 'Loveplace',
superPower: 'computers',
};
- 强制 对于用逗号分隔的多行结构,始终加上最后一个逗号。
eslint:comma-dangle
这样可以使增删行更加容易,也会使 git diffs
更清晰。Babel
等编译器会在编译后的代码里帮我们去掉最后额外的逗号,因此不必担心在旧浏览器中的问题。
/*
* bad - 没有结尾逗号时,新增一行的 git diff 示例
*/
const hero = {
firstName: 'Florence',
- lastName: 'Nightingale'
+ lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing']
};
/*
* good - 有结尾逗号时,新增一行的 git diff 示例
*/
const hero = {
firstName: 'Florence',
lastName: 'Nightingale',
+ inventorOf: ['coxcomb chart', 'modern nursing'],
};
/* bad */
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
/* good */
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
/* bad */
function createHero(
firstName,
lastName,
inventorOf
) {
// ...
}
createHero(
firstName,
lastName,
inventorOf
);
/* good */
function createHero (
firstName,
lastName,
inventorOf,
) {
// ...
}
/*
* good - 需注意,使用扩展运算符的元素后面不能加逗号
*/
function createHero(
firstName,
lastName,
inventorOf,
...heroArgs
) {
// ...
}
块
- 【推荐】始终使用大括号包裹代码块。
eslint: curly,nonblock-statement-body-position
- 多行代码块必须用大括号包裹
/* bad */
if (foo)
bar();
baz(); // 这一行并不在 if 语句里
/* good */
if (foo) {
bar();
baz();
}
- 代码块只有一条语句时,可以省略大括号,并跟控制语句写在同一行。但出于一致性和可读性考虑,不推荐这样做
/* bad */
if (foo)
return false;
/*
* bad - 允许但不推荐
*/
if (foo) return false;
/* good */
if (foo) {
return false;
}
- 强制对于非空代码块,大括号的换行方式采用
Egyptian Brackets
风格。eslint: brace-style
,具体规则如下:
- 左大括号
{
前面不换行,后面换行 - 右大括号
}
前面换行 - 右大括号
}
后面是否换行有两种情况:- 3.1 如果
}
终结了整个语句,如条件语句、函数或类的主体,则需要换行 - 3.2 如果
}
后面存在 else、catch、while 等语句,或存在逗号、分号、右小括号)
,则不需要换行
- 3.1 如果
/*
* bad - else 应与 if 的 } 放在同一行
*/
if (foo) {
thing1();
}
else
thing2();
}
/* good */
if (foo) {
thing1();
} else {
thing2();
}
- 【推荐】对于空代码块,且不在类似
if...else...
或try..catch..finally..
的多块结构中时,可以立即将大括号闭合。eslint:brace-style
/* good */
function doNothing() {}
- 如果空代码块在多块结构中,则仍需要按上一条非空块的规则换行:
/* bad */
if (condition) {
// …
} else if (otherCondition) {} else {
// …
}
/* good */
if (condition) {
// …
} else if (otherCondition) {
} else {
// …
}
/* bad */
try {
// …
} catch (e) {}
/* good */
try {
// …
} catch (e) {
}
- 强制不要让代码中出现空代码块,这会使阅读者感到困惑。如果必须使用空块,需在块内写明注释。
eslint: no-empty
/* bad */
if (condition) {
thing1();
} else {
}
/* good */
if (condition) {
thing1();
} else {
// TODO I haven’t determined what to do.
}
空格
- 强制块的左大括号
{
前有一个空格。eslint:space-before-blocks
/* 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',
});
- 强制控制语句(if、while 等)的左小括号 ( 前有一个空格。声明函数时,函数名和参数列表之间无空格。
eslint:keyword-spacing
/* bad */
if(isJedi) {
fight ();
}
/* good */
if (isJedi) {
fight();
}
/* bad */
function fight () {
console.log ('Swooosh!');
}
/* good */
function fight() {
console.log('Swooosh!');
}
- 强制小括号内部两侧无空格。
eslint: space-in-parens
/* bad */
function bar( foo ) {
return foo;
}
/* good */
function bar(foo) {
return foo;
}
/* bad */
if ( foo ) {
console.log( foo );
}
/* good */
if (foo) {
console.log(foo);
}
- 强制方括号内部两侧无空格。
eslint: array-bracket-spacing
/* bad */
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
/* good */
const foo = [1, 2, 3];
console.log(foo[0]);
- 强制大括号内部两侧有空格。
eslint: object-curly-spacing
/* bad */
const foo = {clark: 'kent'};
/* good */
const foo = { clark: 'kent' };
- 强制运算符两侧有空格,除了一元运算符。
eslint:space-infix-ops
/* bad */
const x=y+5;
/* good */
const x = y + 5;
/* bad */
const isRight = result === 0? false: true;
/* good */
const isRight = result === 0 ? false : true;
/*
* bad - 一元运算符与操作对象间不应有空格
*/
const x = ! y;
/* good */
const x = !y;
- 强制定义对象字面量时,不允许所谓的「水平对齐」,即 key、value 之间应该有且只有一个空格。
eslint: key-spacing
/* bad */
{
a : 'short',
looooongname: 'long',
}
/* good */
{
a: 'short',
looooongname: 'long',
}
- 强制在使用多个(大于两个)方法链式调用时进行换行缩进,把点. 放在前面以强调这是方法调用而不是新语句。
eslint:newline-per-chained-call no-whitespace-before-property
/* 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 - 大于 2 个方法的链式调用才需要进行换行
*/
const leds = stage.selectAll('.led').data(data);
空行
- 【推荐】在文件末尾保留一行空行。
eslint: eol-last
.统一在文件末尾保留一行空行,即用一个换行符结束文件:
/*
* bad - 文件末尾未保留换行符
*/
import { foo } from './Foo';
// ...
export default foo;
/*
* bad - 文件末尾保留了2个换行符
*/
import { foo } from './Foo';
// ...
export default foo;↵
↵
/* good */
import { foo } from './Foo';
// ...
export default foo;↵
- 强制块的开始和结束不能是空行。
eslint: padded-blocks
/* bad */
function bar() {
console.log(foo);
}
/* good */
function bar() {
console.log(foo);
}
/* bad */
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
/* good */
if (baz) {
console.log(qux);
} else {
console.log(foo);
}
- 【参考】在块末和新语句间插入一个空行。
/* 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;
最大字符数和最大行数
- 【推荐】单行最大字符数:
100
。eslint: max-len
.过长的单行代码不易阅读和维护,需要进行合理换行。 单行代码最多不能超过 100 个字符,除了以下两种情况:- 字符串和模板字符串
- 正则表达式
/* bad */
const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
/* good */
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://foo.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
/* good */
$.ajax({
method: 'POST',
url: 'https://foo.com/',
data: { name: 'John' },
})
.done(() => console.log('Congratulations!'))
.fail(() => console.log('You have failed this city.'));
-
【推荐】文件最大行数:
1000
。eslint: max-lines
过长的文件不易阅读和维护,最好对其进行拆分。 -
【推荐】函数最大行数:
80
。eslint: max-lines-per-function
过长的函数不易阅读和维护,最好对其进行拆分。