51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Eslint

# 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() {
		// ...
	}
}

以下情况不受此规则影响:

  • 通过 letconst 声明变量或常量
  • 把函数表达式赋值给变量

# '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️-✅️}

禁止把 MathJSON 这样的内置对象作为函数进行调用。虽然它们的首字母是大写的,但它们并不是一个构造函数。

# '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 === NaNfoo !== NaN 这样的做法,因为这样判断的结果不符合预期。可以使用 isNaN() 函数来完成这个任务。

事实上,在 ES6+ 环境中,建议使用 Number.isNaN() 来检测 NaN,它更健壮一些。

扩展阅读: Number.isNaN() @ MDN (opens new window)

# '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.callerarguments.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 怎么知道哪些变量是全局变量并且只读?我们在配置文件中会声明 envglobals 字段,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️-✅️}

禁止将受限的名字(比如 NaNInfinityundefined 等)作为变量名、参数名。

# '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 有变量提升效果,但它的初始赋值并不会被提升。为避免误解,禁止这种做法。

  • letconst 声明变量之前存在 "短暂死区",在此区域内使用变量会引发报错。

    // ⛔ 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() 之前不允许使用 thissuper 关键字是,否则会产生 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️-🛠️}

ifelsewhiledo-whilefor 等语句的主体为单行且没有写成块形式时,需要把整个语句写成一行,不得换行。

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 默认值:

  • 单词型操作符(比如 typeofdelete)之后加空格。
  • 符号型操作符(比如 ++!)前后都不加空格。

# '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️-🛠️}

[不限] 指定当正则表达式字面量出现在语句中间时,是否需要加括号来避免视觉上的歧义(被误认为是除法运算)。

赞(2)
未经允许不得转载:工具盒子 » Eslint