# Eslint {#eslint}
# ESLint 规则总览 {#eslint-规则总览}
# 图例 {#图例}
- ℹ️ ------ 点击此图标可以访问每条规则对应的 ESLint 官方文档。
- ✅️️ ------ 表示此规则属于 ESLint 官方推荐规则。
- 🛠️️ ------ 表示此规则可自动修复。
# 第一部分:疑似写错的情况 {#第一部分-疑似写错的情况}
# 'for-direction': [2]
^ℹ️ (opens new window) ✅️^ {#for-direction-2-i️-✅️}
for
判断条件中的变量朝着相反的方向变化(这意味判断永远无法达成),会导致死循环。这通常是写错了。
# 'getter-return': [2]
^ℹ️ (opens new window) ✅️^ {#getter-return-2-i️-✅️}
属性的 getter 一定要有显式的返回值,即使返回 undefined
也应该显式地写出来。
# 'no-async-promise-executor': [2]
^ℹ️ (opens new window) ✅️^ {#no-async-promise-executor-2-i️-✅️}
传给 Promise 构造函数的执行函数不能是异步函数。
# 'no-compare-neg-zero': [2]
^ℹ️ (opens new window) ✅️^ {#no-compare-neg-zero-2-i️-✅️}
禁止出现 foo === -0
这样的判断,这个判断的行为可能不符合作者的预期。在业务代码中写出这个判断极可能是笔误。
# 'no-cond-assign': [2, 'always']
^ℹ️ (opens new window) ✅️^ {#no-cond-assign-2-always-i️-✅️}
禁止在 if
/while
/for
等判断条件中写赋值语句,以免错看成判断;也有可能本意是想写判断,但错写成了赋值。
# 'no-constant-condition': [2]
^ℹ️ (opens new window) ✅️^ {#no-constant-condition-2-i️-✅️}
禁止在 if
/while
/for
等判断条件中出现永远不变的判断结果。这种代码通常是因为调试代码忘了删除而导致的。
# 'no-control-regex': [2]
^ℹ️ (opens new window) ✅️^ {#no-control-regex-2-i️-✅️}
禁止在正则表达式中出现控制字符。没有理由这样做。
# 'no-debugger': process.env.NODE_ENV === 'production' ? [2] : [0]
^ℹ️ (opens new window) ✅️^ {#no-debugger-process-env-node-env-production-2-0-i️-✅️}
禁止在代码中通过 debugger
调用调试器。不过在开发阶段是允许的。
# 'no-dupe-args': [2]
^ℹ️ (opens new window) ✅️^ {#no-dupe-args-2-i️-✅️}
禁止函数出现重名的参数。出现这种代码通常是因为笔误。
# 'no-dupe-keys': [2]
^ℹ️ (opens new window) ✅️^ {#no-dupe-keys-2-i️-✅️}
禁止对象字面量出现重名的 key。出现这种代码通常是因为笔误。
# 'no-duplicate-case': [2]
^ℹ️ (opens new window) ✅️^ {#no-duplicate-case-2-i️-✅️}
禁止 switch
语句出现重复的 case。出现这种代码通常是因为笔误。
# 'no-empty': [2, { 'allowEmptyCatch': true }]
^ℹ️ (opens new window) ✅️^ {#no-empty-2-allowemptycatch-true-i️-✅️}
禁止出现空代码块。
// ⛔
if (foo) {
} else {
return false
}
空的 catch 块是允许的。
// 🆗
try {
doSomething()
} catch (e) {}
# 'no-empty-character-class': [2]
^ℹ️ (opens new window) ✅️^ {#no-empty-character-class-2-i️-✅️}
禁止正则表达式中出现空的字符集合(比如 /foo[]bar/
中的 []
)。包含空集合的正则表达式无法匹配任何字符串,很可能是笔误。
# 'no-ex-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-ex-assign-2-i️-✅️}
禁止在 catch (e) {...}
块内对捕获到的异常(e
)重新赋值。没有理由这样做,很有可能是笔误。
# 'no-extra-boolean-cast': [2]
^ℹ️ (opens new window) ✅️^ {#no-extra-boolean-cast-2-i️-✅️}
禁止不必要的布尔值转换。在 if
语句或三元表达式等的判断条件中,表达式或值会被自动转换为布尔值,无需手动转换。比如 if (!!foo) {...}
与 if (foo) {...}
是等效的。
此时手动转换会让读代码的人困惑。
# 'no-func-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-func-assign-2-i️-✅️}
禁止对已声明的函数重新赋值。我们一般不会主动这样做,很有可能是从别处拷代码过来时出现重名了。
# 'no-import-assign': [2]
^ℹ️ (opens new window)^ {#no-import-assign-2-i️}
禁止对模块导入的绑定重新赋值。这种做法会引发运行时错误。
# 'no-inner-declarations': [2, 'both']
^ℹ️ (opens new window) ✅️^ {#no-inner-declarations-2-both-i️-✅️}
禁止在 if () { ... }
等内层代码块内部声明函数或用 var
声明变量。这些做法往往有损代码可读性,比如声明提升可能带来意外的代码行为;或者在不同的 ES 模式下行为不确定或不合法。
// ⛔
if (foo) {
var a = 1
}
// ⛔
if (foo) {
function bar() {
// ...
}
}
以下情况不受此规则影响:
- 通过
let
或const
声明变量或常量 - 把函数表达式赋值给变量
# 'no-invalid-regexp': [2]
^ℹ️ (opens new window) ✅️^ {#no-invalid-regexp-2-i️-✅️}
禁止向 RegExp()
构造函数传入不合法的字符串,这种做法会引发运行时错误。在日常开发中,建议尽可能使用正则表达式字面量。
# 'no-irregular-whitespace': [2]
^ℹ️ (opens new window) ✅️^ {#no-irregular-whitespace-2-i️-✅️}
禁止在代码中的出现非常规的空白符(比如零宽空格等)。这些特殊字符可能引发解析错误,或者对正常的调试和重构带来困扰。这些字符往往是从别处拷代码时混进来的,或者是误按快捷键输入的。
如果需要在字符串中包含这些非常规空白符,建议使用其 Unicode 形式。比如 let foo = '\u2008'
。
# 'no-misleading-character-class': [2]
^ℹ️ (opens new window) ✅️^ {#no-misleading-character-class-2-i️-✅️}
禁止在正则表达式的字符集合中使用多码位的 Unicode 字符,这样做通常无法得到期望的结果。应该在这个场景下使用单码位的 Unicode 字符。
# 'no-obj-calls': [2]
^ℹ️ (opens new window) ✅️^ {#no-obj-calls-2-i️-✅️}
禁止把 Math
、JSON
这样的内置对象作为函数进行调用。虽然它们的首字母是大写的,但它们并不是一个构造函数。
# 'no-regex-spaces': [2]
^ℹ️ (opens new window) ✅️^ {#no-regex-spaces-2-i️-✅️}
禁止正则表达式中出现多个连续空格。因为很难一眼看清空格的数量。
建议在正则表达式中使用 {n}
来表达空格的重复数量,比如 /foo {3}bar/
。
# 'no-sparse-arrays': [2]
^ℹ️ (opens new window) ✅️^ {#no-sparse-arrays-2-i️-✅️}
禁止通过数组字面量生成稀疏数组("稀疏数组" 是指那些不是每个坑都填了值的数组)。在日常开发中不太有理由使用这个特性,大多数情况下是多打了逗号导致的,比如本意想写 [1, 2]
但写成了 [1,,2]
,就产生了一个稀疏数组。
如果确实需要生成一个稀疏数组,可以使用 Array()
来构造,比如 new Array(3)
会生成一个坑数为 3 的稀疏数组。
# 'no-unexpected-multiline': [2]
^ℹ️ (opens new window) ✅️^ {#no-unexpected-multiline-2-i️-✅️}
防止多行代码被(意外地)解析为连续的运算表达式。在采用 "句末不写分号" 风格的代码中比较容易出现这种情况:当第一行末尾没有分号,而第二行开头是 (
或 [
等字符时,第二行会视为紧接上一行代码的延续,这往往与预期不符。
此时需要在这两行代码之间加分号或 void
关键字,以阻断这种 "粘连效应"。
# 'no-unreachable': [2]
^ℹ️ (opens new window) ✅️^ {#no-unreachable-2-i️-✅️}
禁止出现不可达的代码,比如 return
/throw
/break
语句之后的代码是永远不会执行到的。我们一般不会主动这样写,很有可能调试代码忘了删了。
# 'no-unsafe-finally': [2]
^ℹ️ (opens new window) ✅️^ {#no-unsafe-finally-2-i️-✅️}
禁止在 finally
块中出现 return
/throw
等中止代码流程的语句。因为 finally
块中这些语句的实际执行时机很可能与开发者的预期不符,从而引发 bug。
# 'no-unsafe-negation': [2]
^ℹ️ (opens new window) ✅️^ {#no-unsafe-negation-2-i️-✅️}
禁止对 in
/instanceof
操作符的左侧值使用(意图不明确的)!
运算。比如我们写 !key in object
的本意可能是 !(key in object)
而不是 (!key) in object
,但实际的运算顺序是后者。
# 'use-isnan': [2]
^ℹ️ (opens new window) ✅️^ {#use-isnan-2-i️-✅️}
禁止在检测 NaN
时使用 foo === NaN
或 foo !== NaN
这样的做法,因为这样判断的结果不符合预期。可以使用 isNaN()
函数来完成这个任务。
事实上,在 ES6+ 环境中,建议使用 Number.isNaN()
来检测 NaN
,它更健壮一些。
# 'valid-typeof': [2]
^ℹ️ (opens new window) ✅️^ {#valid-typeof-2-i️-✅️}
强制在做 typeof
判断时总是与合理的值进行比较。比如 typeof foo === 5
永远都不可能相等,没有比较的意义。我们一般不会主动这样写,但笔误无法避免,比如我们很可能会把 'string'
错写成 'stirng'
或 'String'
。
# 第二部分:促进最佳实践 {#第二部分-促进最佳实践}
# 'curly': [2, 'multi-line', 'consistent']
^ℹ️ (opens new window)^ {#curly-2-multi-line-consistent-i️}
约束 if
/while
/for
等语句的代码块是否加大括号:
- 当这些代码块是单条语句且写成一行时,允许不加大括号;其它情况必须加大括号。
- 另外,对同一个
if
/else if
/else
链中的所有代码块来说,要求它们在大括号的写法上保持一致。
这是一条跟代码风格有关的规则,但设置它的目的不是为了统一代码风格,而是为了提升代码可读性,减少误解。
是否要写大括号的约束如下:
// ✅ 单行语句,写成一行,可以加大括号
if (!foo) { return false }
// ✅ 单行语句,写成一行,也可以不加大括号
if (!foo) return false
// ✅ 单行语句,另起一行,需要加大括号
if (!foo) {
return false
}
// ✅ 多行语句,需要加大括号
if (foo) {
foo++
return foo
}
// ⛔
if (!foo)
return false
// ⛔
if (foo) return {
foo: foo,
bar: bar
}
大括号一致性的约束如下:
// ✅ 同一个 if/else if/else 链中的写法要统一
if (foo) foo()
else bar()
// ✅ 同一个 if/else if/else 链中的写法要统一
if (a === 1) {
a++
foo(a)
} else {
foo(b)
}
// ⛔
if (a === 1) {
a++
foo(a)
} else foo(b)
# 'default-param-last': [2]
^ℹ️ (opens new window)^ {#default-param-last-2-i️}
函数的可选参数(有默认值的参数)必须是在最后的。如果可选参数排在非可选参数之前,则该参数其实无法实现可选的效果。
# 'dot-location': [2, 'property']
^ℹ️ (opens new window)^ {#dot-location-2-property-i️}
如果要在 .
操作符这里换行,那么 .
是跟着对象留在上一行,还是跟着方法换到下一行?考虑到链式调用语句的易读性,这条规则要求把 .
放在行首。
// ✅
$('.wrapper > a')
.first()
.addClass('foo')
.html('bar')
// ✅
$('.wrapper > a').first()
.addClass('foo')
.html('bar')
# 'eqeqeq': [2]
^ℹ️ (opens new window)^ {#eqeqeq-2-i️}
当我们用 ==
或 !=
来判断两个不同类型的值时,JS 会采用一些不那么直观易记的判断规则。为避免产出无法预料的 bug,这条规则禁止使用 ==
和 !=
,我们应该总是使用 ===
或 !==
来进行判断。
# 'no-caller': [2]
^ℹ️ (opens new window)^ {#no-caller-2-i️}
在某些情况下,arguments.caller
和 arguments.callee
很好用,但由于 ES5 的严格模式已经禁用了这两者,我们也不应该再使用它们了。
# 'no-case-declarations': [2]
^ℹ️ (opens new window) ✅️^ {#no-case-declarations-2-i️-✅️}
这条规则禁止 let
/const
/function
/class
等词法声明出现在 case
/default
子句中。先看看这样做有什么问题吧:
// ⛔
switch (foo) {
case 1:
let x = 1
fn(x)
break
case 2:
bar(x)
break
default:
foobar()
}
我们在 case 1
中声明了 x
变量,这个变量在整个 switch
代码块中都是可见的,也话是说 case 2
中传给 bar(x)
的实参就是这个 x
,但只有当代码运行到 case 1
分支时 x
才会被初始化,因此当代码运行到 case 2
分支时会产生 ReferenceError。
有可能 case 2
的代码本意是想访问更上层作用域中的 x
变量,因此,如果我们只是想在某个 case
子句中创建一个局部变量,那就需要把子句包进一个代码块中:
// ✅
switch (foo) {
case 1: {
let x = 1
fn(x)
break
}
case 2:
bar(x)
break
default:
foobar()
}
# 'no-empty-function': [2]
^ℹ️ (opens new window)^ {#no-empty-function-2-i️}
禁止出现空函数(啥事也不做的函数)。很可能是忘了写函数体。
# 'no-empty-pattern': [2]
^ℹ️ (opens new window) ✅️^ {#no-empty-pattern-2-i️-✅️}
禁止在解构中出现无意义的解构模式:
// ⛔ 不会生成任何变量
let {a: {}} = foo
这往往是一个笔误,代码的本意很可能是这样的:
// 💭 为变量 a 指定一个默认值
let {a = {}} = foo
# 'no-eval': [2]
^ℹ️ (opens new window)^ {#no-eval-2-i️}
eval()
是 JS 中的一个特殊的函数,它有诸多问题,在日常开发中似乎没有理由使用它。
# 'no-extend-native': [2]
^ℹ️ (opens new window)^ {#no-extend-native-2-i️}
扩展 Object
/Array
/Function
等原生对象可能产生不可预料的副作用,在日常开发中似乎也没有理由这样做。如果要 polyfill,交给 core.js 或 babel-preset-env 等专门的库或工具来实现,不要自己写。
# 'no-extra-bind': [2]
^ℹ️ (opens new window)^ {#no-extra-bind-2-i️}
如果一个函数内部没有用到 this
关键字,则没有必要对它 .bind()
。
# 'no-extra-label': [2]
^ℹ️ (opens new window)^ {#no-extra-label-2-i️}
标签(label)可以帮助我们在多层嵌套的循环中 break
/continue
指定的循环。但如果不存在嵌套的情况,也就没必要加标签了,此时加标签反而令人困惑。
# 'no-fallthrough': [2]
^ℹ️ (opens new window) ✅️^ {#no-fallthrough-2-i️-✅️}
"Case 穿透" 是 switch
的一个有意思的特性,但有时候也是个坑。因此完全禁用这种行为。
# 'no-floating-decimal': [2]
^ℹ️ (opens new window)^ {#no-floating-decimal-2-i️}
禁止浮点数在小数点之前或之后省略 0
的写法。
# 'no-global-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-global-assign-2-i️-✅️}
禁止修改只读的全局变量。
ESLint 怎么知道哪些变量是全局变量并且只读?我们在配置文件中会声明 env
和 globals
字段,ESLint 会通过它们来判断。
# 'no-implicit-coercion': [2, { 'allow': ['!!', '+'] }]
^ℹ️ (opens new window)^ {#no-implicit-coercion-2-allow-i️}
禁用隐式的类型转换,因为代码意图往往不清晰。比如:
// ⛔
var bar = ~foo.indexOf('.')
这行代码令人摸不着头脑,它的本意是这样的(判断字符串的包含关系):
// 💭
var bar = foo.indexOf('.') !== -1
还有一些类型转换的方法,相对比较易读,是允许的:
// 🆗
var b = !!foo // to boolean
var n = +foo // to number
var s = '' + foo // to string
当然最清晰的写法还是显式转换:
// ✅
var b = Boolean(foo)
var n = Number(foo)
var s = String(foo)
# 'no-implied-eval': [2]
^ℹ️ (opens new window)^ {#no-implied-eval-2-i️}
setTimeout()
等函数可能会隐式地调用 eval()
,禁止这种情况。
// ⛔
setTimeout("alert('foo')", 1000)
应该使用下面的写法来代替:
// ✅
setTimeout(function() {
alert('foo')
}, 1000)
# 'no-lone-blocks': [2]
^ℹ️ (opens new window)^ {#no-lone-blocks-2-i️}
禁止不必要的代码块包裹。
# 'no-multi-str': [2]
^ℹ️ (opens new window)^ {#no-multi-str-2-i️}
禁止在字符串中使用转义符来生成多行字符串:
// ⛔ 'foo' 和 'bar' 之间通过转义符生成了一个换行
let str = 'foo\
bar'
应该使用字符串拼接来生成多行字符串,或直接使用 ES6 模板字符串:
// ✅ 字符串拼接
let str = 'foo\n' +
'bar'
// ✅ 通过数组来拼接多行字符串
let str = [
'foo',
'bar'
].join('\n')
// ✅ 模板字符串
let str = `foo
bar`
# 'no-new-func': [2]
^ℹ️ (opens new window)^ {#no-new-func-2-i️}
禁止使用 Function()
来生成函数,它的问题与 eval()
类似。有些模板引擎会用它来编译模板,但在日常开发中似乎没有理由使用它。
# 'no-octal': [2]
^ℹ️ (opens new window) ✅️^ {#no-octal-2-i️-✅️}
禁止使用八进制数字字面量,因为不易读。
// ⛔
let i = 010 // 8
建议使用 ES6 新增的八进制数字字面量写法:
// ✅
let i = 0o10
# 'no-octal-escape': [2]
^ℹ️ (opens new window)^ {#no-octal-escape-2-i️}
禁止在字符串中使用八进制转义序列,因为 ES5 已经弃用此特性,而且这种写法不易读。
# 'no-return-assign': [2, 'always']
^ℹ️ (opens new window)^ {#no-return-assign-2-always-i️}
虽然 return
允许接一个赋值表达式,但这种写法令人困惑:
// ⛔
function fn (bar) {
return foo = bar + 1
}
它的效果是返回 bar + 1
,但本意很可能是想返回 foo === bar + 1
但写错了。
# 'no-self-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-self-assign-2-i️-✅️}
禁止把一个变量赋值给自己。
// ⛔
foo = foo
// ⛔ 通过解构把变量赋值给自己
[a, b] = [a, c]
在某些情况下,我们需要把一个对象的属性赋值给这个属性。这样做看似无意义,但实际上是通过 setter 来触发副作用(比如有些时候可以绕过浏览器 bug 等等)。因此这种情况是允许的。
// 🆗
foo.bar = foo.bar
# 'no-self-compare': [2]
^ℹ️ (opens new window)^ {#no-self-compare-2-i️}
禁止对两个相同的变量进行比较,这往往是写错了。
# 'no-sequences': [2]
^ℹ️ (opens new window)^ {#no-sequences-2-i️}
禁用不必要的 ,
操作符。绝大多数时候它都是不直观、不易读的。除了 for
循环以外,在日常开发中似乎没有理由使用它。
# 'no-throw-literal': [2]
^ℹ️ (opens new window)^ {#no-throw-literal-2-i️}
禁止 throw
一个字面量,应该总是抛出一个 Error 对象。
# 'no-unmodified-loop-condition': [2]
^ℹ️ (opens new window)^ {#no-unmodified-loop-condition-2-i️}
如果循环的判断条件不会发生变化,则在运行时会产生死循环。这种情况应该是写错了。
# 'no-unused-expressions': [2, { 'allowShortCircuit': true, 'allowTernary': true }]
^ℹ️ (opens new window)^ {#no-unused-expressions-2-allowshortcircuit-true-allowternary-true-i️}
禁止无作用的表达式。一个表达式的计算结果被丢弃,则视为 "无作用",一般是写错了。
不过代码中有一些比较常见实践也属于这种情况,因此这条规则作为特例放行:
// 🆗 利用短路来实现逻辑判断
a && b()
// 🆗 利用三元表达式来实现逻辑判断
a ? b() : c()
# 'no-unused-labels': [2]
^ℹ️ (opens new window) ✅️^ {#no-unused-labels-2-i️-✅️}
标签(label)没有被任何 continue
/break
语句用到,将被视为代码写错了。
# 'no-useless-call': [2]
^ℹ️ (opens new window)^ {#no-useless-call-2-i️}
Function#call()
和 Function#apply()
可以指定某个方法执行时的 this
指向,很有用。但如果代码中使用这两个函数但并没改变 this 指向,将被视为代码写错了。
# 'no-useless-catch': [2]
^ℹ️ (opens new window) ✅️^ {#no-useless-catch-2-i️-✅️}
如果我们在 catch
代码块中只是把捕获到的错误再抛出去,那这一层 catch
其实是没有必要的。禁止这种行为。
# 'no-with': [2]
^ℹ️ (opens new window) ✅️^ {#no-with-2-i️-✅️}
禁止使用 with
语句。
# 'prefer-promise-reject-errors': [2]
^ℹ️ (opens new window)^ {#prefer-promise-reject-errors-2-i️}
要求 Promise.reject()
只能抛出 Error
对象。
# 'prefer-regex-literals': [2]
^ℹ️ (opens new window)^ {#prefer-regex-literals-2-i️}
我们可以通过 RegExp()
构造函数来生成正则表达式,但这种写法有坑,因为传给它的字符串需要考虑反斜杠的转义问题,一不小心就会写错。
// ⛔ 需要时刻提醒自己:要写两个反斜杠!!!
const reMobileNumber = new RegExp('^1\\d{10}$')
因此,如果有可能的话,我们应该用正则表达式字面量来替代这种写法。
// ✅
const reMobileNumber = /^1\d{10}$/
# 'require-await': [2]
^ℹ️ (opens new window)^ {#require-await-2-i️}
要求 async
函数中总是有 await
语句。
# 第三部分:变量相关 {#第三部分-变量相关}
# 'no-delete-var': [2]
^ℹ️ (opens new window) ✅️^ {#no-delete-var-2-i️-✅️}
禁止 delete
变量。只应该 delete
对象的某个属性。
# 'no-shadow-restricted-names': [2]
^ℹ️ (opens new window) ✅️^ {#no-shadow-restricted-names-2-i️-✅️}
禁止将受限的名字(比如 NaN
、Infinity
、undefined
等)作为变量名、参数名。
# 'no-undef': [2]
^ℹ️ (opens new window) ✅️^ {#no-undef-2-i️-✅️}
禁止引用一个未定义的变量,这可能导致一个 ReferenceError,或者无意中创建了一个全局变量。
# 'no-use-before-define': [2, { 'functions': false }]
^ℹ️ (opens new window)^ {#no-use-before-define-2-functions-false-i️}
禁止在定义变量之前就使用它。因为:
-
虽然
var
有变量提升效果,但它的初始赋值并不会被提升。为避免误解,禁止这种做法。 -
let
和const
声明变量之前存在 "短暂死区",在此区域内使用变量会引发报错。// ⛔ alert(bar) // => undefined var bar = 1
// ✅ var bar = 1 alert(bar) // => 1
// ✅ var bar alert(bar) // => undefined bar = 1
函数声明的提升相对安全,允许先使用后声明。
// 🆗
foo()
function foo() { /* ... */ }
# 第四部分:代码风格相关 {#第四部分-代码风格相关}
# 'new-cap': [2, { capIsNew: false, properties: true }]
^ℹ️ (opens new window)^ {#new-cap-2-capisnew-false-properties-true-i️}
要求构建函数必须是首字母大写;如果对象的属性作为构建函数,则这个属性也必须是首字母大写。
不过首字母大写的函数可以单独调用,并不限制它只能用于 new
操作符。
# 'new-parens': [2]
^ℹ️ (opens new window)^ {#new-parens-2-i️}
构造函数在调用时必须写小括号。
// ⛔
let person = new Person
// ✅
let person = new Person()
# 'no-array-constructor': [2]
^ℹ️ (opens new window)^ {#no-array-constructor-2-i️}
禁止通过 Array()
构造函数来创建数组,应该用数组字面量:
// ⛔
let arr = new Array(1, 2, 3)
// ✅
let arr = [1, 2, 3]
如果你只传一个整数值给 Array()
以便创建一个稀疏数组,是允许的:
// 🆗
let arr = new Array(19)
# 'no-bitwise': [2]
^ℹ️ (opens new window)^ {#no-bitwise-2-i️}
禁用所有的位运算符。
// ⛔
let a = b & c
// ⛔
if (foo | bar) {/* ... */}
理论上业务代码中不太可能会用到位运算,写出位运算多半是手滑敲错了。比如上面这两行代码的本意可能是这样的:
// 💭
let a = b && c
// 💭
if (foo || bar) {/* ... */}
# 'no-new-object': [2]
^ℹ️ (opens new window)^ {#no-new-object-2-i️}
禁止通过 Object()
构造函数来创建对象,应该用对象字面量:
# 'unicode-bom': [2]
^ℹ️ (opens new window)^ {#unicode-bom-2-i️}
采用 Unicode 编码的文本文件可以在文件的开始用几个字节标注 "字节顺序"(BOM)。
BOM 对 JS 文件没有害处,但对 PHP 文件有非常大的害处(PHP 无法忽略文件开头的那几个 BOM 字节,导致功能异常)。由于我们的系统中默认一律采用 UTF-8,不需要通过 BOM 来指定,因此建议你配置好自己的编辑器,统一关闭生成 BOM 的功能。
# 第五部分:ES6 相关 {#第五部分-es6-相关}
# 'constructor-super': [2]
^ℹ️ (opens new window) ✅️^ {#constructor-super-2-i️-✅️}
只有派生 class 才允许调用 super()
。
# 'no-class-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-class-assign-2-i️-✅️}
禁止给 class 赋值。
# 'no-const-assign': [2]
^ℹ️ (opens new window) ✅️^ {#no-const-assign-2-i️-✅️}
禁止给常量赋值。
# 'no-dupe-class-members': [2]
^ℹ️ (opens new window) ✅️^ {#no-dupe-class-members-2-i️-✅️}
禁止 class 的方法或属性出现重名。出现这种代码通常是因为笔误。
# 'no-new-symbol': [2]
^ℹ️ (opens new window) ✅️^ {#no-new-symbol-2-i️-✅️}
Symbol()
看起来像个构造函数,但实际上它是单独调用的。禁止通过 new
操作符来调用它。
# 'no-this-before-super': [2]
^ℹ️ (opens new window) ✅️^ {#no-this-before-super-2-i️-✅️}
派生 class 的构造方法在调用 super()
之前不允许使用 this
和 super
关键字是,否则会产生 ReferenceError。
# 'require-yield': [2]
^ℹ️ (opens new window) ✅️^ {#require-yield-2-i️-✅️}
Generator 函数体必须包含 yield
关键字。
# ESLint 规则总览 - 代码风格约定 {#eslint-规则总览-代码风格约定}
# 'array-bracket-newline': [2, 'consistent']
^ℹ️ (opens new window) 🛠️^ {#array-bracket-newline-2-consistent-i️-🛠️}
指定数组和类似语法结构的中括号内侧是否换行:要求首尾换行行为一致。
# 'array-bracket-spacing': [2, 'never']
^ℹ️ (opens new window) 🛠️^ {#array-bracket-spacing-2-never-i️-🛠️}
指定数组和类似语法结构的中括号内侧是否加空格:不加。
# 'array-element-newline': [2, 'consistent']
^ℹ️ (opens new window) 🛠️^ {#array-element-newline-2-consistent-i️-🛠️}
指定数组成员之间是否换行:要求同一数组内的行为一致。
# 'block-spacing': [2, 'always']
^ℹ️ (opens new window) 🛠️^ {#block-spacing-2-always-i️-🛠️}
指定代码块的花括号内侧是否加空格:加空格。
# 'brace-style': [0]
^ℹ️ (opens new window) 🛠️^ {#brace-style-0-i️-🛠️}
[不限] 指定花括号的书写风格。
这条规则目前还没有类似 allowStroustrupIfCommentBetween
的选项,实际使用不太方便,因此暂不开启。
# 'camelcase': [2, { ... }]
^ℹ️ (opens new window)^ {#camelcase-2-i️}
要求变量名必须采用驼峰拼写,不得采用 snake_case。不过,解构语法中的属性名是允许 snake_case 的;对象的属性名是允许 snake_case 的;Vue 插件在 Vue 原型上绑定的方法名可以使用 $_camelCase
。
# 'capitalized-comments': [0]
^ℹ️ (opens new window) 🛠️^ {#capitalized-comments-0-i️-🛠️}
[不限] 注释的首字母是否大写。
# 'comma-dangle': [2, 'always-multiline']
^ℹ️ (opens new window) 🛠️^ {#comma-dangle-2-always-multiline-i️-🛠️}
在由逗号分隔的列表(数组字面量、对象字面量、函数参数列表、模块导入导出清单等)中,结尾是否写逗号。
# 'comma-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#comma-spacing-2-i️-🛠️}
指定逗号前后是否加空格:取 ESLint 默认值(逗号前不加空格,逗号后加空格)。
# 'comma-style': [2]
^ℹ️ (opens new window) 🛠️^ {#comma-style-2-i️-🛠️}
指定当需要在逗号处换行时的行为:只能在逗号后换行(即逗号在行末)。
# 'computed-property-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#computed-property-spacing-2-i️-🛠️}
指定对象的计算式属性名的中括号内侧是否加空格:不加。
# 'consistent-this': [0]
^ℹ️ (opens new window)^ {#consistent-this-0-i️}
[不限] 指定 this
的别名允许哪些命名。
# 'eol-last': [2]
^ℹ️ (opens new window) 🛠️^ {#eol-last-2-i️-🛠️}
要求文件末尾必须有一个行结束符(换行符)。
# 'func-call-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#func-call-spacing-2-i️-🛠️}
指定函数调用的函数名和小括号之间是否加空格:不加。
# 'func-name-matching': [0]
^ℹ️ (opens new window)^ {#func-name-matching-0-i️}
[不限] 要求函数名与它被赋值到的变量名(或属性名)是否需要保持一致。
# 'func-names': [0]
^ℹ️ (opens new window)^ {#func-names-0-i️}
[不限] 要求函数表达式是否是具名的。
# 'func-style': [2, 'declaration', { allowArrowFunctions: true }]
^ℹ️ (opens new window)^ {#func-style-2-declaration-allowarrowfunctions-true-i️}
定义函数有两种方式:(1) 函数声明,(2) 把函数表达式赋值给变量。此规则要求使用前者。
不过,把箭头函数赋值给变量是允许的。
# 'function-call-argument-newline': [2, 'consistent']
^ℹ️ (opens new window) 🛠️^ {#function-call-argument-newline-2-consistent-i️-🛠️}
指定函数调用的各个参数之间是否换行:要求各参数的行为一致。
# 'function-paren-newline': [2, 'consistent']
^ℹ️ (opens new window) 🛠️^ {#function-paren-newline-2-consistent-i️-🛠️}
指定包裹函数参数的小括号内侧是否换行:要求首尾换行行为一致。
# 'id-blacklist': [0]
^ℹ️ (opens new window)^ {#id-blacklist-0-i️}
[不限] 指定标识符命名的黑名单。
# 'id-length': [2, { ... }]
^ℹ️ (opens new window)^ {#id-length-2-i️}
指定标识符至少要有多长。除了 e
x
y
z
w
h
i
j
_
$
等常用的单字符变量名以外,至少要达到两个字符。
对象属性的命名不受此规则影响。
# 'id-match': [0]
^ℹ️ (opens new window)^ {#id-match-0-i️}
[不限] 指定标识符命名要满足的模式。
# 'implicit-arrow-linebreak': [2]
^ℹ️ (opens new window) 🛠️^ {#implicit-arrow-linebreak-2-i️-🛠️}
指定当箭头函数采用简写语法时,箭头后是否换行:取 ESLint 默认值(不换行)。
# 'indent': [2, 'tab', { 'SwitchCase': 1 }]
^ℹ️ (opens new window) 🛠️^ {#indent-2-tab-switchcase-1-i️-🛠️}
指定缩进风格:采用 tab 字符作为缩进。switch
语句内的 case
子句需要缩进。
# 'jsx-quotes': [0]
^ℹ️ (opens new window) 🛠️^ {#jsx-quotes-0-i️-🛠️}
[不限] 指定 JSX 中标签属性的引号风格。
# 'key-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#key-spacing-2-i️-🛠️}
指定对象字面量中属性名和属性值之间是否加空格:冒号前不加空格,冒号后加空格。
let obj1 = {
a: value,
bcde: 42,
fg: foobar(),
}
let obj2 = { foo: 1, bar: 2 }
当对象字面量写成多行时,允许在冒号后使用连续多个空格来纵向对齐属性值:
let obj1 = {
a: value,
bcde: 42,
fg: foobar(),
}
# 'keyword-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#keyword-spacing-2-i️-🛠️}
指定关键字前后是否加空格:取 ESLint 默认值(前后都加空格,但在遇到冲突时服从其它加空格规则)。
# 'line-comment-position': [0]
^ℹ️ (opens new window)^ {#line-comment-position-0-i️}
[不限] 指定注释的书写位置是独占一行还是写在代码右侧。
# 'linebreak-style': [2]
^ℹ️ (opens new window) 🛠️^ {#linebreak-style-2-i️-🛠️}
换行符采用 LF
(UNIX 风格)。
# 'lines-around-comment': [0]
^ℹ️ (opens new window) 🛠️^ {#lines-around-comment-0-i️-🛠️}
[不限] 指定注释前后是否要添加空行。
# 'lines-between-class-members': [0]
^ℹ️ (opens new window) 🛠️^ {#lines-between-class-members-0-i️-🛠️}
[不限] 指定类成员之间是否要添加空行。
# 'max-depth': [2]
^ℹ️ (opens new window)^ {#max-depth-2-i️}
指定代码块允许嵌套的最大层数:取 ESLint 默认值(4 层)。
# 'max-len': [2, { ... }]
^ℹ️ (opens new window)^ {#max-len-2-i️}
指定单行代码允许的最大长度:
- 单行代码或注释的最大长度为 120 字符。
- 一级缩进按 4 个字符计算。
- 位于行末的注释不记在内。
- 允许 URL 导致的超长情况。
- 允许正则表达式字面量导致的超长情况。
- 允许字符串字面量或模板字符串导致的超长情况。
# 'max-lines': [0]
^ℹ️ (opens new window)^ {#max-lines-0-i️}
[不限] 指定单个文件允许的最大行数。
# 'max-lines-per-function': [0]
^ℹ️ (opens new window)^ {#max-lines-per-function-0-i️}
[不限] 指定单个函数允许的最大行数。
这条规则目前还没有类似 ignoreTopLevelFunctions
的选项,实际使用不太方便,因此暂不开启。
# 'max-nested-callbacks': [2]
^ℹ️ (opens new window)^ {#max-nested-callbacks-2-i️}
指定回调函数允许嵌套的最大层数:取 ESLint 默认值(10 层)。
# 'max-params': [2, 5]
^ℹ️ (opens new window)^ {#max-params-2-5-i️}
指定函数参数允许的最大数量:5 个。
# 'max-statements': [0]
^ℹ️ (opens new window)^ {#max-statements-0-i️}
[不限] 指定单个函数允许包含的语句的最大数量。
每个变量声明语句也算一个语句,这条规则很难衡量实际的代码复杂度,因此暂不开启。
# 'max-statements-per-line': [2]
^ℹ️ (opens new window)^ {#max-statements-per-line-2-i️}
指单行代码允许包含的语句的最大数量:取 ESLint 默认值(每行最多一个语句)。
# 'multiline-comment-style': [0]
^ℹ️ (opens new window) 🛠️^ {#multiline-comment-style-0-i️-🛠️}
[不限] 指定多行注释的风格。
# 'multiline-ternary': [0]
^ℹ️ (opens new window)^ {#multiline-ternary-0-i️}
[不限] 指定三元运算表达式的换行风格。
# 'new-cap': [0]
^ℹ️ (opens new window)^ {#new-cap-0-i️}
(已收入 essential
配置包中。)
# 'new-parens': [0]
^ℹ️ (opens new window) 🛠️^ {#new-parens-0-i️-🛠️}
(已收入 essential
配置包中。)
# 'newline-per-chained-call': [2, { ignoreChainWithDepth: 3 }]
^ℹ️ (opens new window) 🛠️^ {#newline-per-chained-call-2-ignorechainwithdepth-3-i️-🛠️}
指定链式调用的每个方法是否需要换行:需要换行。
如果链式调用深度在 3 级以内,则允许写成一行。
# 'no-array-constructor': [0]
^ℹ️ (opens new window)^ {#no-array-constructor-0-i️}
(已收入 essential
配置包中。)
# 'no-bitwise': [0]
^ℹ️ (opens new window)^ {#no-bitwise-0-i️}
(已收入 essential
配置包中。)
# 'no-continue': [0]
^ℹ️ (opens new window)^ {#no-continue-0-i️}
[不限] 禁止使用 continue
语句。
# 'no-inline-comments': [0]
^ℹ️ (opens new window)^ {#no-inline-comments-0-i️}
[不限] 指定注释是否要独占一行(是否可以与代码写在同一行)。
# 'no-lonely-if': [2]
^ℹ️ (opens new window) 🛠️^ {#no-lonely-if-2-i️-🛠️}
else
块内如果只有一个单独的 if
语句,则应该合并为 else if
。
# 'no-mixed-operators': [0]
^ℹ️ (opens new window)^ {#no-mixed-operators-0-i️}
[不限] 当表达式中连续使用同类型操作符时,需要用括号显式标出运算优先级。
# 'no-mixed-spaces-and-tabs': [2]
^ℹ️ (opens new window) ✅️️^ {#no-mixed-spaces-and-tabs-2-i️-✅️️}
不允许混用空格和 tab 来实现缩进。
JSDoc 或类似的文档型注释的每行开头的空格不受此规则影响。
# 'no-multi-assign': [0]
^ℹ️ (opens new window)^ {#no-multi-assign-0-i️}
[不限] 是否允许连环赋值。
# 'no-multiple-empty-lines': [2, { max: 2 }]
^ℹ️ (opens new window) 🛠️^ {#no-multiple-empty-lines-2-max-2-i️-🛠️}
指定允许连续空行的数量:取 ESLint 默认值(2 个空行)。
# 'no-negated-condition': [0]
^ℹ️ (opens new window)^ {#no-negated-condition-0-i️}
[不限] 是否允许在一分为二的判断条件中出现否定判断条件。
# 'no-nested-ternary': [0]
^ℹ️ (opens new window)^ {#no-nested-ternary-0-i️}
[不限] 是否允许出现嵌套的三元运算表达式。
# 'no-new-object': [0]
^ℹ️ (opens new window)^ {#no-new-object-0-i️}
(已收入 essential
配置包中。)
# 'no-plusplus': [0]
^ℹ️ (opens new window)^ {#no-plusplus-0-i️}
[不限] 是否允许出现 ++
运算符。
# 'no-restricted-syntax': [0]
^ℹ️ (opens new window)^ {#no-restricted-syntax-0-i️}
[不限] 是否禁止某些特定语法。
# 'no-tabs': [0]
^ℹ️ (opens new window)^ {#no-tabs-0-i️}
[不限] 是否禁用 tab 字符。
# 'no-ternary': [0]
^ℹ️ (opens new window) 🛠️^ {#no-ternary-0-i️-🛠️}
[不限] 是否禁用三元运算表达式。
# 'no-trailing-spaces': [2]
^ℹ️ (opens new window) 🛠️^ {#no-trailing-spaces-2-i️-🛠️}
禁止行末出现空白符(空格、tab 等)。
# 'no-underscore-dangle': [0]
^ℹ️ (opens new window)^ {#no-underscore-dangle-0-i️}
[不限] 是否允许在标识符的头尾使用下划线(_
)。
# 'no-unneeded-ternary': [2]
^ℹ️ (opens new window) 🛠️^ {#no-unneeded-ternary-2-i️-🛠️}
禁止出现不必要的三元运算表达式。
# 'no-whitespace-before-property': [2]
^ℹ️ (opens new window) 🛠️^ {#no-whitespace-before-property-2-i️-🛠️}
对象与属性之间不加空格。
foo.bar()
let z = x[y]
# 'nonblock-statement-body-position': [2]
^ℹ️ (opens new window) 🛠️^ {#nonblock-statement-body-position-2-i️-🛠️}
当 if
、else
、while
、do-while
、for
等语句的主体为单行且没有写成块形式时,需要把整个语句写成一行,不得换行。
if (foo === 1) bar()
# 'object-curly-newline': [2, { consistent: true }]
^ℹ️ (opens new window) 🛠️^ {#object-curly-newline-2-consistent-true-i️-🛠️}
指定对象和类似语法结构的大括号内侧是否换行:要求首尾换行行为一致。
# 'object-curly-spacing': [2, 'always']
^ℹ️ (opens new window) 🛠️^ {#object-curly-spacing-2-always-i️-🛠️}
指定对象和类似语法结构的大括号内侧是否加空格:加空格。
# 'object-property-newline': [2, { allowAllPropertiesOnSameLine: true }]
^ℹ️ (opens new window) 🛠️^ {#object-property-newline-2-allowallpropertiesonsameline-true-i️-🛠️}
对象字面量的各个属性必须独占一行,除非所有属性都写在同一行。
# 'one-var': [2, 'never']
^ℹ️ (opens new window) 🛠️^ {#one-var-2-never-i️-🛠️}
指定同一作用域中的声明语句是否需要合并:不合并,每个声明语句只声明一个变量。
# 'one-var-declaration-per-line': [2, 'initializations']
^ℹ️ (opens new window) 🛠️^ {#one-var-declaration-per-line-2-initializations-i️-🛠️}
当同一条声明语句声明多个变量时,初始化的变量必须独占一行。
# 'operator-assignment': [0]
^ℹ️ (opens new window) 🛠️^ {#operator-assignment-0-i️-🛠️}
[不限] 是否要求使用 x += 4
简化 x = x + 4
。
# 'operator-linebreak': [2, 'after']
^ℹ️ (opens new window) 🛠️^ {#operator-linebreak-2-after-i️-🛠️}
只能在运算符的右侧换行。
# 'padded-blocks': [0]
^ℹ️ (opens new window) 🛠️^ {#padded-blocks-0-i️-🛠️}
[不限] 是否禁止在代码块的内侧插入空行。
# 'padding-line-between-statements': [0]
^ℹ️ (opens new window) 🛠️^ {#padding-line-between-statements-0-i️-🛠️}
[不限] 是否在语句之间插入空行。
# 'prefer-exponentiation-operator': [0]
^ℹ️ (opens new window) 🛠️^ {#prefer-exponentiation-operator-0-i️-🛠️}
[不限] 是否要求使用指数运算符 **
代替 Math.pow()
。
⚠️ 注意:此规则的前提是运行环境或解析环境支持 ES2016 语法,比如:
- 代码会经过 Babel 6+ / Vue CLI 3+ 处理。
- 代码运行于 Node.js 7+。
# 'prefer-object-spread': [0]
^ℹ️ (opens new window) 🛠️^ {#prefer-object-spread-0-i️-🛠️}
[不限] 是否要求使用对象展开语法来代替 Object.assign()
。
⚠️ 注意:此规则的前提是运行环境或解析环境支持 ES2016 语法,比如:
- 代码会经过 Babel 6+ / Vue CLI 3+ 处理。
- 代码运行于 Node.js 8+。
# 'quote-props': [2, 'consistent']
^ℹ️ (opens new window) 🛠️^ {#quote-props-2-consistent-i️-🛠️}
指定对象字面量的各个属性是否需要加引号:要求所有属性行为一致。
# 'quotes': [2, 'single', { avoidEscape: true }]
^ℹ️ (opens new window) 🛠️^ {#quotes-2-single-avoidescape-true-i️-🛠️}
优先使用单引号。当字符串内容包含单引号时,为避免转义,可以字符串可以使用双引号来包裹。
# 'semi': [2, 'never']
^ℹ️ (opens new window) 🛠️^ {#semi-2-never-i️-🛠️}
采用 "无分号" 风格。
# 'semi-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#semi-spacing-2-i️-🛠️}
指定分号前后是否加空格:取 ESLint 默认值(分号前不加空格,分号后加空格)。
# 'semi-style': [0]
^ℹ️ (opens new window) 🛠️^ {#semi-style-0-i️-🛠️}
[不限] 指定分号的书写位置(句名或句首)。
# 'sort-keys': [0]
^ℹ️ (opens new window)^ {#sort-keys-0-i️}
[不限] 给对象字面量的属性排序。
# 'sort-vars': [0]
^ℹ️ (opens new window) 🛠️^ {#sort-vars-0-i️-🛠️}
[不限] 声明变量时给变量排序。
# 'space-before-blocks': [2]
^ℹ️ (opens new window) 🛠️^ {#space-before-blocks-2-i️-🛠️}
指定代码块之前是否加空格:取 ESLint 默认值(加空格)。
# 'space-before-function-paren': [2, { ... }]
^ℹ️ (opens new window) 🛠️^ {#space-before-function-paren-2-i️-🛠️}
指定函数参数的小括号之前是否加空格:
- 匿名函数:要加。比如:
function () {}
- 具名函数:不加。比如:
function foo() {}
- 异步函数:要加。比如:
async () => {}
# 'space-in-parens': [2, 'never']
^ℹ️ (opens new window) 🛠️^ {#space-in-parens-2-never-i️-🛠️}
指定小括号内侧是否加空格:取 ESLint 默认值(不加)。
# 'space-infix-ops': [2]
^ℹ️ (opens new window) 🛠️^ {#space-infix-ops-2-i️-🛠️}
指定中缀操作符的前后否加空格:取 ESLint 默认值(加空格)。
# 'space-unary-ops': [2]
^ℹ️ (opens new window) 🛠️^ {#space-unary-ops-2-i️-🛠️}
指定一元操作符的前后否加空格:取 ESLint 默认值:
- 单词型操作符(比如
typeof
、delete
)之后加空格。 - 符号型操作符(比如
++
、!
)前后都不加空格。
# 'spaced-comment': [0]
^ℹ️ (opens new window) 🛠️^ {#spaced-comment-0-i️-🛠️}
指定注释的 //
之后和 /*
*/
的内侧是否需要加空格:加空格。
// this is a comment
/* this is a comment */
以下情况不受此规则影响:
- 这种形式的分隔线:
//--------
- 这种形式的分隔线:
//========
- 这种形式的分隔线:
//++++++++
- 这种形式的区段标题:
//////////////////// Title ////////////////////
以下特殊字符会视为注释标记的一部分,在它们之后仍然需要加空格:
- 文档型注释:
/** this is a doc comment */
- 这种形式的特殊注释:
/*! this comment remained after minifying */
- 这种形式的特殊注释:
/// <reference path="..." />
# 'switch-colon-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#switch-colon-spacing-2-i️-🛠️}
指定 switch
语句中的 case
/default
子句的冒号是否加空格:取 ESLint 默认值(冒号前不加空格,冒号后加空格)。
# 'template-tag-spacing': [2]
^ℹ️ (opens new window) 🛠️^ {#template-tag-spacing-2-i️-🛠️}
指定模板字符串与它的 tag 函数之间是否加空格:取 ESLint 默认值(不加)。
# 'unicode-bom': [0]
^ℹ️ (opens new window) 🛠️^ {#unicode-bom-0-i️-🛠️}
(已收入 essential
配置包中。)
# 'wrap-regex': [0]
^ℹ️ (opens new window) 🛠️^ {#wrap-regex-0-i️-🛠️}
[不限] 指定当正则表达式字面量出现在语句中间时,是否需要加括号来避免视觉上的歧义(被误认为是除法运算)。