原文链接:https://www.teamten.com/lawrence/programming/keep-if-clauses-side-effect-free.html
“译注:说到 副作用 ,前端er应该都很熟悉或者听过这个词,不过你是Vue派还是React阵营,这个词都是我们编码中绕不过的。
在日常编程中,if
语句无处不在。它们是我们控制流程、编写逻辑判断的基础。但你是否留意过,if
语句中不经意的 副作用 ,可能正在悄悄损害你代码的清晰性与可维护性?
本文分享一个简单却被广泛忽视的最佳实践:避免在 if
语句中执行有副作用的操作。
✋ 避免在 if
中执行具有副作用的函数
我们来看一个常见的例子:
if (enqueueMessage(message)) {
// ...
}
这段代码看似简洁,但却隐藏着一个问题:enqueueMessage()
这个函数是否只是检查条件?还是实际上执行了“将消息加入队列”的操作?
if
语句的本职是判断条件是否为真,而不是顺带完成某个动作。将带有副作用的操作写在 if
判断中,会使逻辑变得模糊难懂。更清晰的写法是将其提取出来:
boolean success = enqueueMessage(message);
if (success) {
// ...
}
这不仅让语义更明确,也更像自然语言:“如果成功了,就……”。
✅ 为什么要将判断逻辑分离?
我们再来看一个类似的例子:
if (flushQueue() == 0) {
// ...
}
这段代码同样存在歧义。是判断某个状态?还是执行了某种行为?把操作结果提取出来,可以显著提高代码可读性:
int itemsFlushed = flushQueue();
if (itemsFlushed == 0) {
// ...
}
这种写法使得“行为”和“判断”一目了然,也更便于调试和维护。
⚠️ 真实场景中的问题案例
假设你看到如下代码:
if (!categorySeen.add(categoryID)) continue;
乍一看,这似乎是要跳过已存在的 categoryID
,但 add()
方法本身具有副作用 —— 它会修改 categorySeen
集合。这就会让读者误以为是在判断是否包含,而实际上是试图“添加并判断是否是新增项”。
更清晰的做法是:
boolean isNew = categorySeen.add(categoryID);
if (isNew) {
// ...
}
现在逻辑很明确了:先尝试添加,然后判断是否是新添加的。
❌ 不要在 if
的一行中混合副作用
以下这个例子也容易出问题:
if (queueNeedsFlushing() && flushQueue() == 0) {
// ...
}
这段代码使用了逻辑与(&&
)来“顺带”执行 flushQueue()
,这是非常危险的做法。原因是逻辑短路运算符的本意是用于副作用为零的表达式组合,比如:
if (count > 0 && total/count >= MIN_AVERAGE) { ... }
if (name != null && name.endsWith(\".png\")) { ... }
一旦混入副作用函数,就可能导致行为混乱、不易发现的问题。
正确写法应当是:
if (queueNeedsFlushing()) {
int itemsFlushed = flushQueue();
if (itemsFlushed == 0) {
// ...
}
}
这段代码虽然行数更多,却更加明确、安全,且不会隐藏操作行为。
“译注:真的不建议强行把几条语句合并到一条,能够拆开就尽量拆开,见识过100多行的三元运算符,那一刻只能对前辈默念几句“听我说谢谢你, **”。 百度原来有句slogan是“简单可依赖”,我认为这句话用在coding上更恰当,尽量写简单易懂的语句,对他人好一点,也对几个月之后的自己好一点。
✅ 总结:逻辑清晰比代码简短更重要
我们总是倾向于写“更短”的代码,但这往往以牺牲可读性为代价。而在判断逻辑中保持副作用的显式分离,是一个简单却极其有用的习惯。
“三行代码的清晰,永远胜过一行代码的含糊。
保持 if
语句“纯净”,只承担判断职责,是让代码更具可读性、可维护性的关键一步。
我的观点
这篇文章,我认为最重要的东东就是下面几个:
if
语句不要包含副作用,尽量保持 if
语句内是简单的变量判断if
语句内的函数调用,尽量提前拆分到单独的一行,可以通过函数返回值的语义化命名,提高代码可读性- 时刻警惕短路运算
&&
,当左值是 false
的时候,右侧表达式不会执行! - 对照上面这点,也要警惕或运算符
||
,当左值为 true
的时候,右侧表达式也不会执行!
阅读原文:原文链接
该文章在 2025/9/8 9:35:20 编辑过