Почему операторы "продолжить" плохи в JavaScript?


в книге Javascript: Хорошие Части Дуглас Крокфорд, это все, что автор должен сказать о продолжении заявления:

The continue оператор переходит в верхнюю часть цикла. Я никогда не видел кусок кода, который не был улучшен путем оптимизации его убрать continue заявление.

это действительно смущает меня. Я знаю, что у Крокфорда есть некоторые очень самоуверенные взгляды на JavaScript, но это просто звучит полностью неправильно для меня.

прежде всего,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 не особенно полезно в этом конкретном примере, но он демонстрирует тот факт, что он уменьшает глубину вложенности. В более сложном коде это потенциально может повысить читаемость.

Крокфорд не дает никаких объяснений, почему continue не должно быть используется, так есть ли какое-то более глубокое значение за этим мнением, которое мне не хватает?

6 57

6 ответов:

утверждение нелепо. continue можно злоупотреблять, но это часто помогает читабельности.

типичное использование:

for (somecondition)
{
    if (!firsttest) continue;

    some_provisional_work_that_is_almost_always_needed();

    if (!further_tests()) continue;

    do_expensive_operation();
}

цель состоит в том, чтобы избежать кода "лазанья", где у вас есть глубоко вложенные условные обозначения.

редактировать, чтобы добавить:

Да, это в конечном счете субъективная. вот моя метрика для принятия решения.

отредактировано в последний раз:

этот пример слишком простой, конечно, и вы всегда можете заменить вложенные условные выражения вызовами функций. Но тогда вам, возможно, придется передавать данные во вложенные функции по ссылке, что может создать проблемы рефакторинга по крайней мере так же плохо, как те, которые вы пытаетесь избежать.

Я лично на другой стороне, чем большинство здесь. Проблема обычно не с continue шаблоны,но с более глубоко вложенными, где возможные пути кода могут стать труднодоступными.

но даже ваш пример с одним 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();
}

оба эти работы, но если вы случайно смешать эти стили вы получаете бесконечный цикл:

Пример 3

rec = getrec();

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

    rec = getrec();
}

Это может быть частью того, почему он не любит по-прежнему.

продолжить является чрезвычайно полезным инструментом для сохранения вычислительных циклов в алгоритмах. Конечно, он может быть неправильно использован, но так же может и любое другое ключевое слово или подход. При стремлении к производительности может быть полезно использовать обратный подход к дивергенции пути с условным утверждением. Продолжение может облегчить обратное, позволяя пропускать менее эффективные пути, когда это возможно.

собственно, из всего анализа кажется:

  1. Если у вас есть неглубокие петли-не стесняйтесь использовать continue iff это улучшает читаемость (кроме того, там мая быть какой прирост производительности?).
  2. Если у вас есть глубокие вложенные циклы (что означает, что у вас уже есть комок волос, чтобы распутать при повторном факторе), избегание продолжения может оказаться полезным с точки зрения надежности кода.

в защиту Дугласа Крокфорда, я чувствую, что его рекомендации, как правило, склоняются к защитное Программирование, что, честно говоря, кажется хорошим подходом для "идиотской проверки" кода на предприятии.

лично я никогда не слышал ничего плохого об использовании оператора continue. Это правда, что его можно было бы (в большинстве случаев) легко избежать, но нет никаких причин не использовать его. Я считаю, что циклы могут быть намного чище и более читаемыми с помощью инструкций continue.