cssmagic / blog

CSS魔法 - 博客
http://blog.cssmagic.net/
2.81k stars 274 forks source link

如何改善既有 JS 代码:修复常见的 ESLint 报警(二) #78

Open cssmagic opened 6 years ago

cssmagic commented 6 years ago

前言

ESLint 是目前最主流、最强大的 JS 代码校验工具。当我们的代码触发了 ESLint 的报警规则时,ESLint 就会提示错误。

本系列文章将详细讲解那些需要手工介入修复的 ESLint 规则,帮助你顺利地把既有代码迁移到 ESLint 的保护之中。

no-return-assign

禁止 return 一个赋值表达式。

虽然函数允许 return 一个赋值表达式,但这种写法令人困惑:

function foobar (bar) {
    return foo = bar + 1
}

它的效果是返回 bar + 1,但本意很可能是想返回 foo === bar + 1 但写错了。因此,这条规则往往可以帮我们发现代码中的笔误。当你的代码触发这条规则报警时,看一下你的真实意图到底是哪一种情况,然后就可以简单修复了:

有意思的是,到了 ES6 时代,还有一种情况可能会令你无意中触发这条规则。箭头函数令我们的代码更加简洁,用它写回调函数看起来很酷,比如我们在实现 “延时一秒跳转页面” 的需求时,可能会写成这样:

setTimeout(() => location.href = myUrl, 1000)

这行代码顺理成章,一气呵成,但实际上它也会触发 no-return-assign 这条规则。怎么会这样?

我们不妨来复习一下箭头函数的语法设计:为了精简代码噪音,当箭头函数的函数体只有一个 return 语句时,可以同时省略函数体外层花括号({})和 return 关键字。

好,再来看一眼上面这个的箭头函数 () => location.href = myUrl,我们不难反推出它的 “完全体” 实际上是这样的:

() => {
    return location.href = myUrl
}

这正好符合 no-return-assign 这条规则扫描的特征,于是报警。

你可能会觉得这条规则在这里太过敏感了?其实不是。仔细想一下,其实 () => location.href = myUrl 这个箭头函数的行为实际上已经与作者的本意不符了,因为它除了有跳转页面的功能以外,还让函数有了返回值——这超出了作者的初衷。

常言道:我们的本意是什么,就应该把代码写成什么样。在这里,我们对这个箭头的预期就是跳转页面,所以它的行为只需要是这样:

() => {
    location.href = myUrl
}

那么接下来,触发报警的那一行代码改成这样就可以了:

setTimeout(() => { location.href = myUrl }, 1000)

改过之后的代码在简洁性和可读性方面没有任何损失,意图却更加准确了,鼓掌!

no-constant-condition

这条规则禁止在 if/while/for 等判断条件中出现永远不变的判断结果。

比如 if (true) {...} 等。

乍一看你可能会认为 “完全没有道理写出这样的代码呀~”。然而跑一遍 ESLint 就会发现,代码库中这样的情况并不少见!写出这种代码通常有三种原因,分别讨论如下。

原因一:调试代码忘了删

举个日常例子,某功能需要由一个判断条件来决定是否启动,代码会这样写:

if (foo === bar) {
    // 启动某功能
}

在开发调试阶段,你可能需要跳过这个判断,直接启动这个功能,那么代码会临时小改一下:

if (true || foo === bar) {
    // 启动某功能
}

当我们开发完整个功能之后,往往可能忘了把这里的 true || 删掉。幸好在上线之前,ESLint 的 no-constant-condition 规则帮你发现了这一行明显有违常理的代码,业界良心有木有!

原因二:临时下线某功能

有时候我们需要临时下线某功能,为了最小化对代码的改动,往往会这样写:

if (false && foo === bar) {
    // 启动某功能
}

这显然也是过不了 no-constant-condition 规则的。那怎么办?

如果某功能的频繁上线和下线真的是个需求,那不新建一个变量,专门作为它的开关:

let flag = false  // 临时下线
if (flag && foo === bar) {
    // 启动某功能
}

改成这样,不仅代码意图更清晰了,而且 no-constant-condition 也不再报警了,一举两得!

原因三:使用了 while(true) 的写法

有一种编码模式是先创建一个 while (true) {...} 循环,然后在循环体内有条件地通过 break 语句来中止循环:

while (true) {
    // do something
    foo++
    if (foo >= bar) break
}

显然这里的 while (true) 会触发 no-constant-condition 这条规则。

这种写法并不十分常用,也确实不鼓励使用,因为在大多数情况下它并不易读,稍不留神还可能产生死循环;而且它通常可以很容易地用 do/while 改造成更清晰的模式:

do {
    // do something
    foo++
} while (foo < bar)

或者用 for 循环来改写也是不错的:

for (; foo < bar; foo++) {
    // do something
}

当然也不能排除某些逻辑用 while (true) {...} 的写法确实更合适,或很难改成上面两种形式,那你可以用 foo (;;) {...} 来代替它:

for (;;) {
    // do something
    foo++
    if (foo >= bar) break
}

这样就可以简单快速地绕过这条规则了。

(待续……)


本文在 “CSS魔法” 微信公众号首发,扫码立即订阅:

weixin-qrcode


© Creative Commons BY-NC-ND 4.0   |   我要订阅   |   我要打赏