Semi 分号
- 不要使用分号。 eslint:
semi
js
// bad
window.alert('hi');
// good
window.alert('hi')
References 引用
对您的所有引用使用 const
;避免使用 var
。eslint:prefer-const
js
// bad
var a = 1;
var b = 2;
// good
const a = 1;
const b = 2;
避免修改使用 const
声明的变量 。 eslint: no-const-assign
js
// bad
const score = 100
score = 125
如果必须重新分配引用,请使用 let
而不是 var
。ESLint: no-var
js
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
Objects 对象
使用字面量创建对象。eslint: no-new-object
js
// bad
const item = new Object();
// good
const item = {};
使用对象方法简写。eslint: object-shorthand
js
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
使用属性值简写。eslint: object-shorthand
js
const name = 'jason';
// bad
const obj = {
name: name,
};
// good
const obj = {
name,
};
在对象声明的开头对简写的属性进行分组。
js
const name = 'jason';
const age = 18;
// bad
const obj = {
email: 'jason@gmail.com',
name,
age,
};
// good
const obj = {
name,
age,
email: 'jason@gmail.com',
};
字面量对象的key不使用字符串。eslint: quote-props
js
// bad
const bad = {
'foo': 3,
'bar': 4,
'data-blah': 5,
};
// good
const good = {
foo: 3,
bar: 4,
'data-blah': 5,
};
使用解构{...}
来进行浅拷贝,代替Object.assign
eslint: prefer-object-spread
js
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
delete copy.a; // so does this
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
Arrays 数组
使用字面量语法创建数组。eslint: no-array-constructor
js
// bad
const items = new Array();
// good
const items = [];
使用 Array的push 代替直接赋值obj[0]= 'a'
赋值
js
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
使用数组展开 ...
复制数组。
js
// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i += 1) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
在数组方法回调中使用 return 语句。如果函数体由返回一个没有副作用的表达式组成,则可以省略返回eslint: array-callback-return
js
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => x + 1);
// bad - no returned value means `acc` becomes undefined after the first iteration
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
});
// good
[[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
const flatten = acc.concat(item);
return flatten;
});
// bad
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
} else {
return false;
}
});
// good
inbox.filter((msg) => {
const { subject, author } = msg;
if (subject === 'Mockingbird') {
return author === 'Harper Lee';
}
return false;
});
数组少的一行显示,多行则在换行显示
js
// bad
const arr = [
[0, 1], [2, 3], [4, 5],
];
const objectInArray = [{
id: 1,
}, {
id: 2,
}];
const numberInArray = [
1, 2,
];
// good
const arr = [[0, 1], [2, 3], [4, 5]];
const objectInArray = [
{
id: 1,
},
{
id: 2,
},
];
const numberInArray = [
1,
2,
];
Destructuring 解构
对象的属性使用解构访问。eslint: prefer-destructuring
js
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
使用数组解构。eslint: prefer-destructuring
js
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
Strings 字符串
对字符串使用单引号 ''
。eslint: quotes
js
// bad
const name = "Capt. Janeway";
// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;
// good
const name = 'Capt. Janeway';
行超过 100 个字符 依然一行显示,不应该换行或多行拼接显示。 eslint: no-multi-str
js
// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
// bad
const errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
// good
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
使用模板字符串构建字符串,而不是+
拼接。eslint: prefer-template
js
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// bad
function sayHi(name) {
return ['How are you, ', name, '?'].join();
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
模板字符串中变量前后不加空格 。 eslint: template-curly-spacing
js
const message = `Hello, ${ name }` // ✗ avoid
const message = `Hello, ${name}` // ✓ ok
Functions 函数
使用命名函数表达式而不是函数声明。eslint:func-style,func-names
js
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
禁止使用 Function
构造器 。 eslint: no-new-func
js
var sum = new Function('a', 'b', 'return a + b') // ✗ avoid
将立即调用的函数表达式包裹在括号中。eslint:wrap-iife
js
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
使用 rest 语法 ...args
代替 arguments
eslint: prefer-rest-params
js
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
使用默认参数语法而不是更改函数参数。eslint: no-param-reassign
js
// really bad
function handleThings(opts) {
opts = opts || {};
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
始终将默认参数放在最后。eslint: default-param-last
js
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
函数定义中的间距。eslint: space-before-function-paren
js
// bad
const f = function(){};
const g = function (){};
const h = function() {};
// good
const x = function () {};
const y = function a() {};
代码块首尾留空格 。 eslint: space-before-blocks
js
if (admin){...} // ✗ avoid
if (admin) {...} // ✓ ok
使用...
spread语法来调用可变参数函数。eslint: prefer-spread
js
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);
// good
const x = [1, 2, 3, 4, 5];
console.log(...x);
// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
// good
new Date(...[2016, 8, 5]);
函数多个参数调用,多个参数换行,都后接逗号。eslint: function-paren-newline
js
// bad
function foo(bar,
baz,
quux) {
// ...
}
// good
function foo(
bar,
baz,
quux,
) {
// ...
}
// bad
console.log(foo,
bar,
baz);
// good
console.log(
foo,
bar,
baz,
);
点号操作符须与属性需在同一行 。 eslint: dot-location
js
// bad
console.
log('hello')
// good
console
.log('hello')
函数调用时标识符与括号间不留间隔 。 eslint: func-call-spacing
js
// bad
console.log ('hello')
// good
console.log('hello')
嵌套的代码块中禁止再定义函数 。 eslint: no-inner-declarations
js
if (authenticated) {
function setAuthUser () {} // ✗ avoid
}
Arrow Functions 箭头函数
匿名函数或内联函数,使用箭头函数。eslint:prefer-arrow-callback
, arrow-spacing
js
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
使用高阶函数,如果返回值没有副作用,则无需加return,直接返回对象即可。 eslint:arrow-parens
, arrow-body-style
js
// bad
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number, index) => ({
[index]: number,
}));
// No implicit return with side effects
function foo(callback) {
const val = callback();
if (val === true) {
console.log("hello")
}
}
let bool = false;
// bad // 代码报错
foo(() => bool = true);
// good 这里要用对象包裹 才能省略return
foo(() => {
bool = true;
});
如果表达式跨越多行,换行显示
js
// bad
['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
);
// good
['get', 'post', 'put'].map((httpMethod) => (
Object.prototype.hasOwnProperty.call(
httpMagicObjectWithAVeryLongName,
httpMethod,
)
));
高阶函数的箭头函数参数
都加上括号。eslint: arrow-parens
js
// bad
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map((x) => x * x);
避免箭头函数(=>
) 与比较运算符 (<=
, >=
) 混淆。eslint: no-confusing-arrow
js
// bad
const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize;
// good
const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize);
// good
const itemHeight = (item) => {
const { height, largeSize, smallSize } = item;
return height <= 256 ? largeSize : smallSize;
};
箭头函数体的默认不换行,或者括号包裹。eslint: implicit-arrow-linebreak
js
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
Classes & Constructors 类和构造函数
始终使用Class类
。代替 prototype 原型
。
js
// bad
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
};
// good
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
}
}
使用extends继承
进行扩展。
js
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this.queue[0];
};
// good
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}
不要定义空的构造函数或主动调用super的构造函数。eslint: no-useless-constructor
js
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
子类的构造器中一定要调用 super
eslint: constructor-super
js
class Dog {
constructor () {
super() // ✗ avoid
}
}
class Dog extends Mammal {
constructor () {
super() // ✓ ok
}
}
不要扩展原生对象 。 eslint: no-extend-native
js
Object.prototype.age = 21 // ✗ avoid
new
创建对象实例后需要赋值给变量 。 eslint: no-new
js
new Character() // ✗ avoid
const character = new Character() // ✓ ok
使用 this
前请确保 super()
已调用。
eslint: no-this-before-super
js
class Dog extends Animal {
constructor () {
this.legs = 4 // ✗ avoid
super()
}
}
禁止多余的构造器 。 eslint: no-useless-constructor
js
class Car {
constructor () { // ✗ avoid
}
}
Modules 模块
使用es6标准的import
/export
,不用使用 comonjs等非标准的require
js
// 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;
不要使用通配符导入。
js
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
同一个包只import 一个地方。eslint: no-duplicate-imports
js
// bad
import foo from 'foo';
import { named1, named2 } from 'foo';
// good
import foo, { named1, named2 } from 'foo';
不要导出可变绑定。eslint: no-mutable-exports
js
// bad
let foo = 3;
export { foo };
// good
const foo = 3;
export { foo };
单个导出的模块 使用默认导出。eslint:prefer-default-export
js
// bad
export function foo() {}
// good
export default function foo() {}
将所有 import
放在最顶部。eslint: import/first
js
// bad
import foo from 'foo';
foo.init();
import bar from 'bar';
// good
import foo from 'foo';
import bar from 'bar';
foo.init();
超过多个导入应该换行。eslint: object-curly-newline
js
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// good
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';
import的时候不使用扩展名,如:.js
,.vue
eslint: import/extensions
js
// bad
import foo from './foo.js';
import bar from './bar.jsx';
import baz from './baz/index.jsx';
// good
import foo from './foo';
import bar from './bar';
import baz from './baz';
使用高阶函数map(),filter()
代替for-in
或 for-of
这样的循环。eslint: no-iterator
no-restricted-syntax
js
const 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);
import, export 和解构操作中,禁止赋值到同名变量 。 eslint: no-useless-rename
js
import { config as config } from './config' // ✗ avoid
import { config } from './config' // ✓ ok
Properties 属性
访问属性时使用点表示法。eslint:dot-notation
js
const people = {
name: 'jason',
age: 28,
};
// bad
const name = people['name'];
// good
const name = luke.name;
对象属性换行时注意统一代码风格 。 eslint: object-property-newline
js
const user = {
name: 'Jane Doe', age: 30,
username: 'jdoe86' // ✗ avoid
}
const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' } // ✓ ok
const user = {
name: 'Jane Doe',
age: 30,
username: 'jdoe86'
} // ✓ ok
使用动态变量访问属性
时使用括号表示法 []
js
const people = {
name: 'jason',
age: 28,
};
function getProp(prop) {
return people[prop]; // 动态变量
}
const name = getProp('name');
Variables 变量
不要使用 undefined
来初始化变量 。 eslint: no-undef-init
js
let name = undefined // ✗ avoid
let name
name = 'value' // ✓ ok
不连续声明变量,每个变量或赋值使用一个 const
或 let
声明。eslint: one-var
js
// 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';
对所有 const
放一起定义,let
也放一起定义。
js
// 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;
将变量分配到您需要的地方,但将它们放在合理的地方。
js
// 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;
}
不要链式变量声明+赋值。ESLint: no-multi-assign
js
// bad
(function example() {
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`
避免使用一元递增和递减(++
、--
)。ESLINT no-plusplus
js
// 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;
避免在赋值中 =
之前或之后换行。如果您的赋值违反了 max-len
,请用括号括起来。eslint operator-linebreak
。
js
// bad
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo
= 'superLongLongLongLongLongLongLongLongString';
// good
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
不允许未使用的变量。eslint: no-unused-vars
js
// bad
const some_unused_var = 42;
let y = 10; // 这里没有使用上面some_unused_var
y = 5; // 这里没有使用上面some_unused_var
// Unused function arguments.
function getX(x, y) { // y没有被使用
return x;
}
不要对变量使用 delete
操作。
eslint: no-delete-var
js
var name
delete name // ✗ avoid
Comparison Operators & Equality 比较运算符和相等
在 ==
和 !=
上使用 ===
和 !=
。ESLint:EQEqEQ
js
// bad
const x = 100
if (x == 42) { }
const y = 'xxx'
if (y != 'xxx') { }
// good
const x = 100
if (x === 42) { }
const y = 'xxx'
if (y !== 'xxx') { }
条件语句(如 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
js
if ([0] && []) {
// true
// an array (even an empty one) is an object, objects will evaluate to true
}
对布尔值直接比较,但字符串和数字使用显式比较。
js
// bad
if (isValid === true) {
// ...
}
// good
if (isValid) {
// ...
}
// bad
if (name) {
// ...
}
// good
if (name !== '') {
// ...
}
// bad
if (collection.length) {
// ...
}
// good
if (collection.length > 0) {
// ...
}
switch的case和default使用大括号在包裹内容 eslint: no-case-declarations
js
// 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 {}
}
}
三元不应嵌套,通常拆成多个,然后每个单行表达
非要分开则?
和 :
与跟后面代码一行。eslint: no-nested-ternary
文件
js
// bad
const foo = maybe1 > maybe2
? "bar"
: value1 > value2 ? "baz" : null;
// split into 2 separated ternary expressions
const maybeNull = value1 > value2 ? 'baz' : null;
// better
const foo = maybe1 > maybe2
? 'bar'
: maybeNull;
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;
使用|| , !!, ??
代替三元语句。eslint: no-unneeded-ternary
js
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
const quux = a != null ? a : b;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
const quux = a ?? b;
混合运算符时,建议判断都加上括号,||
, &&
分离括号。eslint: no-mixed-operators
js
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// bad
const bar = a ** b - 5 % d;
// bad
// one may be confused into thinking (a || b) && c
if (a || b && c) {
return d;
}
// bad
const bar = a + b / c * d;
// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
// good
const bar = a ** b - (5 % d);
// good
if (a || (b && c)) {
return d;
}
// good
const bar = a + (b / c) * d;
??
主要判断 null
或未定义
。其他0
或者 ''
不应该使用。
js
// bad
const value = 0 ?? 'default';
// returns 0, not 'default'
// bad
const value = '' ?? 'default';
// returns '', not 'default'
// good
const value = null ?? 'default';
// returns 'default'
// good
const user = {
name: 'John',
age: null
};
const age = user.age ?? 18;
// returns 18
代码块短则一行,多应该加上括号 eslint: nonblock-statement-body-position
js
// 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;
}
如果您使用带有 if
和 else
的多行块, else
不独立一行 。eslint: brace-style
js
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
一元运算符后面跟一个空格 。 eslint: space-unary-ops
js
typeof!admin // ✗ avoid
typeof !admin // ✓ ok
Control Statements 控制语句
条件多应该换行显示,判断符号在前面
js
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
thing1();
}
// bad
if (foo === 123 &&
bar === 'abc') {
thing1();
}
// bad
if (foo === 123
&& bar === 'abc') {
thing1();
}
// bad
if (
foo === 123 &&
bar === 'abc'
) {
thing1();
}
// good
if (
foo === 123
&& bar === 'abc'
) {
thing1();
}
// good
if (
(foo === 123 || bar === 'abc')
&& doesItLookGoodWhenItBecomesThatLong()
&& isThisReallyHappening()
) {
thing1();
}
// good
if (foo === 123 && bar === 'abc') {
thing1();
}
不要使用选择运算符代替控制语句。
js
// bad
!isRunning && startRunning();
// good
if (!isRunning) {
startRunning();
}
switch
一定要使用 break
来将条件分支正常中断 。 eslint: no-fallthrough
js
switch (filter) {
case 1:
doSomething() // ✗ avoid
case 2:
doSomethingElse()
}
switch (filter) {
case 1:
doSomething()
break // ✓ ok
case 2:
doSomethingElse()
}
switch (filter) {
case 1:
doSomething()
// fallthrough // ✓ ok
case 2:
doSomethingElse()
}
finally
代码块中不要再改变程序执行流程 。 eslint: no-unsafe-finally
js
try {
// ...
} catch (e) {
// ...
} finally {
return 42 // ✗ avoid
}
请书写优雅的条件语句(avoid Yoda conditions) 。 eslint: yoda
js
if (42 === age) { } // ✗ avoid
if (age === 42) { } // ✓ ok
Comments 注释
对多行注释使用 /** ... */
。
js
// 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;
}
注释放在行上方
js
// 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;
}
注释前加空格。eslint: spaced-comment
js
// 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;
}
使用 FIXME:
注释问题。
js
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
使用 TODO:
注释问题的解决方案。
js
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
如果有更好的实现,尽量不要使用三元表达式。
eslint: no-unneeded-ternary
js
let score = val ? val : 0 // ✗ avoid
let score = val || 0 // ✓ ok
Whitespace 空白
使用设置为 2 个空格的软制表符(空格字符)。eslint: indent
js
// bad
function foo() {
∙∙∙∙let name;
}
// bad
function bar() {
∙let name;
}
// good
function baz() {
∙∙let name;
}
在前大括号前放置 1 个空格。eslint: space-before-blocks
js
// 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',
});
单行代码块两边加空格 。 eslint: block-spacing
js
// bad
function foo () {return true}
// good
function foo () { return true }
在控制语句(if
、while
等)的左括号前放置 1 个空格。在函数调用和声明中,参数列表和函数名称之间不要放置空格。eslint: keyword-spacing
js
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
用空格来衬托运算符。eslint: space-infix-ops
js
// bad
const x=y+5;
// good
const x = y + 5;
使用单个换行符结束文件。ESLint:eol-last
js
// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;
js
// bad
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
↵
js
// good
import { es6 } from './AirbnbStyleGuide';
// ...
export default es6;↵
在块之后和下一个语句之前留一个空行。
js
// 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;
在块里不要多余的空行。eslint: padded-blocks
eslint: no-multiple-empty-lines
js
// bad
function bar() {
console.log(foo);
}
// bad
if (baz) {
console.log(quux);
} else {
console.log(foo);
}
// bad
class Foo {
constructor(bar) {
this.bar = bar;
}
}
// good
function bar() {
console.log(foo);
}
// good
if (baz) {
console.log(quux);
} else {
console.log(foo);
}
不要在括号内添加空格。eslint: space-in-parens
js
// 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
js
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good
const foo = [1, 2, 3];
console.log(foo[0]);
在大括号内添加空格。eslint: object-curly-spacing
js
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
代码过长,需要换行。 ESLint:MAX-LEN
js
// 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;
// better
const foo = 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.'));
逗号前不用空格,逗号后使用空格。eslint: comma-spacing
js
// bad
const arr = [1 , 2];
var foo = 1,bar = 2;
// good
const arr = [1, 2];
var foo = 1, bar = 2;
字面量对象属性的:
后面要有空格 。eslint: key-spacing
js
// bad
const obj = { foo : 42 };
const obj2 = { foo:42 };
// good
const obj = { foo: 42 };
避免在行尾出现尾随空格。eslint: no-trailing-spaces
js
// bad - multiple empty lines
const x = 1;. // .代表空格
// good
const x = 1;
除了缩进,不要使用多个空格 。 eslint: no-multi-spaces
js
const id = 1234 // ✗ avoid
const id = 1234 // ✓ ok
遇到分号时空格要后留前不留 。 eslint: semi-spacing
js
for (let i = 0 ;i < items.length ;i++) {...} // ✗ avoid
for (let i = 0; i < items.length; i++) {...} // ✓ ok
Commas 逗号
数组/对象/属性的逗号都应该在后面。 eslint: comma-style
js
// bad
const story = [
once
, upon
, aTime
];
// good
const story = [
once,
upon,
aTime,
];
// bad
const hero = {
firstName: 'Ada'
, lastName: 'Lovelace'
, birthYear: 1815
, superPower: 'computers'
};
// good
const hero = {
firstName: 'Ada',
lastName: 'Lovelace',
birthYear: 1815,
superPower: 'computers',
};
对象/数组/属性最后一个元素都多加一个逗号 eslint: comma-dangle
js
// bad
const hero = {
firstName: 'Dana',
lastName: 'Scully'
};
const heroes = [
'Batman',
'Superman'
];
// good
const hero = {
firstName: 'Dana',
lastName: 'Scully',
};
const heroes = [
'Batman',
'Superman',
];
// bad
function createHero(
firstName,
lastName,
inventorOf
) {
// does nothing
}
// good
function createHero(
firstName,
lastName,
inventorOf,
) {
// does nothing
}
// good (note that a comma must not appear after a "rest" element)
function createHero(
firstName,
lastName,
inventorOf,
...heroArgs
) {
// does nothing
}
// bad
createHero(
firstName,
lastName,
inventorOf
);
// good
createHero(
firstName,
lastName,
inventorOf,
);
// good (note that a comma must not appear after a "rest" element)
createHero(
firstName,
lastName,
inventorOf,
...heroArgs
);
Type Casting & Coercion 类型转换
字符串转化用String(xx)
, 不用new String()
或obj.toString()
:eslint:no-new-wrappers
js
const reviewScore = 9;
// bad
const totalScore = new String(reviewScore);
// bad
const totalScore = reviewScore + '';
// bad
const totalScore = reviewScore.toString();
// good
const totalScore = String(this.reviewScore);
Numbers:使用 Number
进行类型转换。 parseInt('200', 10)
要传入第二个进制参数。ESLint: no-new-wrappers
js
// bad
const val = parseInt(inputValue);
// good
const val = Number(inputValue);
// good
const val = parseInt(inputValue, 10);
不使用 new Boolean()创建布尔值:eslint:no-new-wrappers
js
const age = 0;
// bad
const hasAge = new Boolean(age);
// good
const hasAge = Boolean(age);
// best
const hasAge = !!age;
Naming Conventions 命名约定
避免使用单字母名称。你的命名要具有描述性。eslint:id-length
js
// bad
function q() {
// ...
}
// good
function query() {
// ...
}
命名对象、函数和实例时使用驼峰命名法。eslint: camelcase
js
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}
// good
const thisIsMyObject = {};
function thisIsMyFunction() {}
仅在命名构造函数或类时使用 PascalCase。ESLint: new-cap
js
// 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',
});
变量前后不要加 __xxxx__
下划线。eslint: no-underscore-dangle
js
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';
// good
this.firstName = 'Panda';
不要保存对this
引用。使用箭头函数或 Function#bind代替。
js
// 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);
};
}
导出默认函数时使用驼峰命名法。您的文件名应与函数名称相同。
js
function makeStyleGuide() {
// ...
}
export default makeStyleGuide;
// 文件名 makeStyleGuide.js
导出构造函数/类/单例/函数库/裸对象时使用 PascalCase。
js
// 构造函数
export default function MyConstructor(name) {
this.name = name;
}
// 类
export default class UserProfile {}
// 单例
export default Logger = { log(msg) { console.log(msg); } };
// 裸对象
export default const AppConfig = {
API_URL: 'https://api.example.com',
ENV: 'production',
};
首字母缩略词和首字母缩略词应始终全部大写或全部小写。
js
// 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 = [
// ...
];
只有当常量直接导出时key值大写。如果导出是对象中的key 还是小写。
js
// 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';
// ---
// bad
export const apiKey = 'SOMEKEY';
// good
export const API_KEY = 'SOMEKEY';
// ---
// bad - 这里不应该大写
export const MAPPING = {
KEY: 'value'
};
// good
export const MAPPING = {
key: 'value',
};
不要使用 JavaScript getter/setter,改用 getVal()
和 setVal('hello')
js
// bad
class Dragon {
get age() {
// ...
}
set age(value) {
// ...
}
}
// good
class Dragon {
getAge() {
// ...
}
setAge(value) {
// ...
}
}
属性/方法是布尔值
,使用 isVal()
或 hasVal()
定义
js
// bad
if (!dragon.age()) {
return false;
}
// good
if (!dragon.hasAge()) {
return false;
}
Events 事件
通过对象做事件的参数。
js
// bad
$(this).trigger('listingUpdated', listing.id);
// good
$(this).trigger('listingUpdated', { listingID: listing.id });
// bad
$(this).on('listingUpdated', (e, listingID) => {
// do something with listingID
});
// good
$(this).on('listingUpdated', (e, data) => {
// do something with data.listingID
});
Standard Library 标准库与其他
使用 Number.isNaN
而不是全局 isNaN
。eslint: no-restricted-globals
js
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
使用浏览器全局变量时加上 window.
前缀。 document
、console
和 navigator
除外。
eslint: no-undef
js
window.alert('hi') // ✓ ok
不要使用 debugger
。 eslint: no-debugger
js
function sum (a, b) {
debugger // ✗ avoid
return a + b
}
不要省去小数点前面的0 。 eslint: no-floating-decimal
js
const discount = .5 // ✗ avoid
const discount = 0.5 // ✓ ok
不要使用标签语句。
eslint: no-labels
js
label:
while (true) {
break label // ✗ avoid
}
使用 __dirname
和 __filename
时尽量避免使用字符串拼接。
eslint: no-path-concat
js
const pathToFile = __dirname + '/app.js' // ✗ avoid
const pathToFile = path.join(__dirname, 'app.js') // ✓ ok
使用 getPrototypeOf
来替代 __proto__
。
eslint: no-proto
js
const foo = obj.__proto__ // ✗ avoid
const foo = Object.getPrototypeOf(obj) // ✓ ok
不要随意更改关键字的值 。 eslint: no-shadow-restricted-names
js
let undefined = 'value' // ✗ avoid
用 throw
抛错时,抛出 Error
对象而不是字符串。
eslint: no-throw-literal
js
throw 'error' // ✗ avoid
throw new Error('error') // ✓ ok
避免不必要的 .call()
和 .apply()
。
eslint: no-useless-call
js
sum.call(null, 1, 2, 3) // ✗ avoid
检查 NaN
的正确姿势是使用 isNaN()
。
eslint: use-isnan
js
if (price === NaN) { } // ✗ avoid
if (isNaN(price)) { } // ✓ ok