Douglas Crockford著の本Javascript:The Good Partsでは、これが著者がcontinueステートメントについて述べなければならないことのすべてです:
continue
ステートメントは、ループの先頭にジャンプします。continue
ステートメントを削除するためにリファクタリングしても改善されなかったコードを見たことはありません。
これは本当に私を混乱させます。 CrockfordがJavaScriptに関して非常に意見のある見解を持っていることは知っていますが、これはまったく間違っているように思えます。
まず、continue
はループの先頭にジャンプするだけではありません。デフォルトでは、次の反復にも進みます。それで、Crockfordの声明は完全に誤った情報ではないのですか?
さらに重要なことは、なぜ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
は悪用される可能性がありますが、多くの場合helpsreadability。
典型的な使用:
for (somecondition)
{
if (!firsttest) continue;
some_provisional_work_that_is_almost_always_needed();
if (!further_tests()) continue;
do_expensive_operation();
}
目標は、条件が深くネストされている「ラザニア」コードを回避することです。
追加するために編集:
はい、これは最終的に主観的です。 ここに決定のためのメトリックがあります。
最後にもう一度編集:
もちろん、この例は単純すぎて、ネストされた条件をいつでも関数呼び出しに置き換えることができます。ただし、ネストされた関数に参照によってデータを渡す必要がある場合があります。これにより、少なくとも回避しようとしているものと同じくらい悪いリファクタリングの問題が発生する可能性があります。
私は個人的にはここの大半よりも反対側にいます。問題は通常、示されているcontinue
パターンではなく、より深くネストされたパターンであり、コードパスが見えにくくなる可能性があります。
しかし、1つのcontinue
を使用した例でさえ、正当であるとの私の意見の改善を示していません。私の経験から、いくつかのcontinue
ステートメントはリファクタリングの悪夢後(特にJavaのような自動リファクタリングに適した静的言語、特に誰かが後でbreak
を置いた場合でも)も))。
したがって、私はあなたが与えた引用にコメントを追加します:
continue
ステートメントを削除するためのリファクタリングは、リファクタリングのさらなる能力を高めます。
そして、内側のループは、例えば抽出関数。このようなリファクタリングは、内側のループが複雑になり、continue
が苦痛になる場合に行われます。
これらは、チームでJavaScriptプロジェクトを専門的に作業した後の私の正直な意見です。ダグラス・クロックフォードが話しているルールには、それぞれのメリットがあります。
ダグラス・クロックフォードは、条件内での割り当てを信じていないため、このように感じるかもしれません。実際、彼のプログラムJSlintは、Javascriptを使用していても、それを許可していません。彼は決して書かない:
例1
while (rec = getrec())
{
if (condition1(rec))
continue;
doSomething(rec);
}
しかし、私は彼がのように書くと推測しています:
例2
rec = getrec();
while (rec)
{
if (!condition(rec))
doSomething(rec);
rec = getrec();
}
これらは両方とも機能しますが、これらのスタイルを誤って混在させると、無限ループが発生します。
例
rec = getrec();
while (rec)
{
if (condition1(rec))
continue;
rec = getrec();
}
これは、彼が続けたくない理由の一部かもしれません。
Continueは、アルゴリズムの計算サイクルを節約するための非常に便利なツールです。もちろん、それは不適切に使用される可能性がありますが、他のすべてのキーワードやアプローチも使用できます。パフォーマンスを追求する場合、条件ステートメントを使用してパスの発散に逆のアプローチをとると便利です。 continueは、可能であれば効率の悪いパスをスキップできるようにすることで、逆を容易にします。
実際、すべての分析から、次のように思われます。
Douglas Crokfordを擁護する上で、彼の推奨は defensive programming に傾く傾向にあると感じています。
個人的には、continueステートメントの使用について悪いことを聞いたことはありません。 (ほとんどの場合)簡単に回避できることは事実ですが、それを使用する理由はありませんnot。ループは、continueステートメントを適切に配置することで、見た目がきれいになり、読みやすくなります。