Подтвердить что ты не робот

Почему в JavaScript недостаточно "утверждать" утверждения?

В книге Javascript: The Good Parts от Douglas Crockford, это все, что автор должен сказать о продолжении заявления:

Оператор 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 не следует использовать, так ли какое-то более глубокое значение для этого мнения, что я не хватает?

4b9b3361

Ответ 1

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

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

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

    some_provisional_work_that_is_almost_always_needed();

    if (!further_tests()) continue;

    do_expensive_operation();
}

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

Отредактировано для добавления:

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

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

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

Ответ 2

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

Но даже ваш пример с одним continue не показывает улучшения, на мой взгляд, которые оправданы. По моему опыту несколько операторов continue представляют собой кошмар для рефакторинга позже (даже для статических языков, которые лучше подходят для автоматического рефакторинга, такого как Java, особенно когда кто-то позже ставит туда break тоже).

Таким образом, я бы добавил комментарий к цитате, которую вы дали:

Рефакторинг для удаления инструкции continue увеличивает вашу способность рефакторировать.

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

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

Ответ 3

Дуглас Крокфорд может чувствовать себя так, потому что он не верит в назначение в условном выражении. Фактически, его программа 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();
}

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

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