JavaScript中为什么“continue”语句不好?

66
在Douglas Crockford的书籍《Javascript: The Good Parts》中,关于continue语句作者只是这样说的:“continue语句跳到循环的顶部。我从来没有看到过一段代码,它不通过重构而变得更好,以消除continue语句。” 这让我非常困惑。我知道Crockford对JavaScript有些非常主观的看法,但这听起来完全是错误的。首先,continue不仅可以跳到循环的顶部,而且默认情况下还会进入下一个迭代。那么Crockford的陈述不就是完全错误的信息吗?更重要的是,我完全不明白为什么continue甚至被认为是不好的。这篇文章提供了似乎是一般假设的原因:为什么在循环内使用continue是个坏主意? 虽然我理解在某些情况下continue可能会使代码难以阅读,但我认为它同样可以使代码更易读。例如:
var someArray=['blah',5,'stuff',7];
for(var i=0;i<someArray.length;i++){
    if(typeof someArray[i]==='number'){
        for(var j=0;j<someArray[i];j++){
            console.log(j);
        }
    }
}

这可以重构为:
var someArray=['blah',5,'stuff',7];
for(var i=0;i<someArray.length;i++){
    if(typeof someArray[i]!=='number'){
        continue;
    }
    for(var j=0;j<someArray[i];j++){
        console.log(j);
    }
}

continue在这个特定的例子中并没有特别有益,但它确实展示了它减少了嵌套深度的事实。在更复杂的代码中,这可能会增加可读性。

Crockford没有解释为什么不应该使用continue,那么这个观点背后是否有一些更深层次的意义我没有理解?


我有同样的感觉,这就是为什么我写了我的帖子。对我有帮助的是,在使用continue语句时,只需想到单词“跳跃”。我认为Crawford先生在设计语言时选择了一个不太好的词:P,特别是因为“跳跃”可以应用于“继续”的逻辑。如果你跳过某些东西,通常也会继续前进。把马拉松赛跑运动员作为一个好的比喻。 - NiCk Newman
6
"Crawford先生"并非设计该语言的人。 - rlemon
1
有人应该写一本名为“JavaScript:好的部分:好的部分”的书。坦白地说,我认为原著中的很多建议都应该带着一颗氯化钠的颗粒,如果不是整个盐矿的话。 - Manngo
3
我越读克罗克福德的文章,越觉得他的观点不值得尊重。他似乎只是一个脾气暴躁的老门卫,拥有完全不合理的品味偏好,但他却把这些包装成经验积累的智慧。 - iono
1
@TylerH 我们能不能把Crockford先生标记为“主观性较强”?哈哈 - twiz
显示剩余3条评论
6个回答

75
这句话荒谬无比。虽然continue会被滥用,但它通常有助于提高可读性。
典型用法:
for (somecondition)
{
    if (!firsttest) continue;
    
    some_provisional_work_that_is_almost_always_needed();

    if (!further_tests()) continue;

    do_expensive_operation();
}

目标是避免出现“千层面”代码,即你有深度嵌套的条件语句。

编辑后添加:

是的,这个目标最终是主观的。这是我的衡量标准。

最后一次编辑:

当然,这个例子太简单了,你总是可以用函数调用替代嵌套条件语句。但是你可能需要通过引用将数据传递到嵌套函数中,这可能会创建重构问题,至少和你试图避免的问题一样糟糕。


我还要补充的是,可读性是主观的,虽然大多数人似乎喜欢使用 continue,但也有其他人可能不喜欢。出于同样的原因,人们讨厌 goto,但它们并非本质上邪恶的(只有滥用 goto 才是邪恶的)。 - Wug
使用 continue 还可以让代码更加符合函数式编程风格,例如:for(a in b) { if (condition1) continue; if (condition2) continue; doSomething(); } 类似于 b.filter(condition1).filter(condition2).forEach(a => ...); - Stephen Chung
我认为"continue"非常难懂。对我来说,"continue"意味着"继续下一行",但这并不是它的实际含义。它的含义是"跳过"或"进入下一次循环迭代",因此任何一个类似的词语都比较好理解。阅读"continue"只会让我感到困惑。 - Juan Perez

8
道格拉斯·克罗克福德可能有这种感觉,是因为他不相信在条件语句中进行赋值操作。实际上,他的程序JSlint甚至不允许你这样做,尽管JavaScript可以。他永远不会写出以下代码: ```javascript if (a = 10) { // do something } ``` 示例1
while (rec = getrec())
{   
    if (condition1(rec))
        continue;

    doSomething(rec);
}

但是,我猜他会写出以下内容:

示例2

rec = getrec();

while (rec)
{   
    if (!condition(rec))
        doSomething(rec);

    rec = getrec();
}

这两种方法都可以使用,但如果不小心混合使用,就会导致无限循环:

示例3

rec = getrec();

while (rec)
{   
    if (condition1(rec))
        continue;

    rec = getrec();
}

这可能是他不喜欢连续性的原因之一。

你说的有道理,但我认为他一般来说也反对使用 while 循环。 - twiz
4
我的观点同样适用于for循环和do循环。他肯定相信某种类型的循环! - Tom Lucas
rec = getrec(); 出现两次,违反了不要重复自己原则。 - Damian Yerrick
@diachedelic 他最新的书是什么?只是一个更新的版本吗? - twiz
@twiz https://howjavascriptworks.com/ - diachedelic
显示剩余3条评论

7
我个人与大多数人的观点不同。问题通常不在于所显示的continue模式,而是更深层次的嵌套模式,可能会使代码路径难以看清。
但即使您的示例只有一个continue,在我看来也没有显示出可以证明改进的合理性。根据我的经验,一些continue语句后续重构时非常难以处理(即使是对于像Java这样更适合自动重构的静态语言,尤其是当其他人在其中加入了break时)。
因此,我会在你给出的引用中添加评论:

重构以删除continue语句可以进一步提高您的重构能力。

内部循环非常适合进行例如提取函数的操作。当内部循环变得复杂时,进行这样的重构,然后continue可能会让它变得痛苦。
这是我在团队中专业从事JavaScript项目后的真实看法,Douglas Crockford谈到的这些规则确实显示了他们的优点。

5
我不确定我了解你的意思。您是否介意举个例子,说明在哪种情况下continue会变成重构的“噩梦”?此外,“提取函数”是什么意思?这是一种设计模式吗? - twiz
2
“提取函数”(也可以在Google中搜索“提取方法”)是一种重构技术,将函数的一部分提取到一个新的独立函数中。即使是这里另一个答案中的简单代码有2个continue语句,也需要重新编写(以摆脱continue语句),以便从for循环的主体中创建一个新函数。当您拥有更多嵌套的continue语句时,清理代码需要花费大量时间。 - jJ'

2
实际上,从所有的分析来看:
  1. 如果您有浅层循环 - 如有必要可使用continue,以提高可读性(同时,也可能会有一些性能提升?)。
  2. 如果您有深度嵌套循环(这意味着在重构时需要解决复杂的问题),避免使用continue可能会从代码可靠性的角度证明是有益的。
为了支持Douglas Crokford,我认为他的建议倾向于defensive programming,老实说,这似乎是一个在企业中“防呆”代码的好方法。

2

Continue是一种在算法中节省计算周期的非常有用的工具。当然,它可能会被不当使用,但其他关键词或方法也可能如此。在追求性能时,采用条件语句的相反方法来处理路径分歧可能会很有用。通过使用continue,可以在可能的情况下跳过效率较低的路径,从而实现这种相反的方法。


1

就我个人而言,我从未听说过使用 continue 语句有什么不好的地方。虽然大部分情况下它可以很容易地避免使用,但没有理由使用它。我发现使用 continue 语句可以使循环代码看起来更简洁、更易读。


非常正确。补充一下你的回答,转译器在生成汇编代码时会在每个循环结尾内部添加一个等效的 continue 语句。因此实际上,continue 语句不仅不是坏的,而且非常好。 - Jack G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接