Циклы FOR, WHILE в JS
Циклы — это фундаментальная концепция программирования, используемая для повторения выполнения блока кода до тех пор, пока не будет выполнено определенное условие.
Цикл можно представить себе в реальной жизни. Например, Вы чистите картошку. Чистка одной картофелины - это тело цикла. Сколько раз повторять тело цикла? Например, 10 раз - тогда у Вас будет 10 чистых картофелин. А можно поставить условие повторения "пока не заполнится сковородка". Или можно поставить условие "никогда не заканчивать" - в программировании разрешены бесконечные циклы.
В JavaScript существует три конструкции для циклов - for, while и do-while.
Реально можно всегда использовать только один вид цикла. Любите for? Никаких проблем, можно быть сеньором и использовать for всегда и везде, и даже не знать о существовании while. Однако, я всё же рассмотрю все три варианта и объясню, какая вообще была изначально задумка у авторов и почему они решили, что нужно так много разных конструкций.
Начнем с while, потому что он самый примитивный.
Цикл `while`
Практическая задача: Вы выполняете операцию, которая должна повторяться до тех пор, пока не будет достигнут определенный уровень точности или пока не будут выполнены некоторые динамические условия, например, когда пользователь вводит правильный пароль. Кроме того, возможна ситуация, что не произойдёт ни одного повторения.
В случае с чисткой картошки - Вы не знаете заранее, сколько картофелин Вам надо, но перед каждой следующей картофелиной Вы проверяете, не полна ли сковородка.
function skovorodka_is_full() { // здесь функция, которая определяет, заполнена ли сковородка } function have_potatoes() { // здесь функция, которая определяет, есть ли еще нечищенная картошка } while (!skovorodka_is_full() && have_potatoes()) { take_new_potato(); clean_potato(); add_clean_potato_to_skovorodka(); }
Почему while идеален в этом случае: Цикл `while` хорошо подходит для ситуаций, когда неизвестно, сколько итераций потребуется до того, как будет достигнуто условие остановки. Кроме того, while допускает ситуацию, когда не происходит ни одного повторения цикла. Например, у Вас нет картошки (обидно, но ситуация основана на реальных событиях!).
Цикл do-while
do-while очень похож на while, но всё же есть существенная разница - условие повторения цикла выполняется не перед телом, а после тела цикла.
Практическая задача: есть ситуации, когда абсолютно бессмысленно делать проверку окончания цикла до совершения хотя бы одной итерации. Например:
- проверять уровень достаточности опьянения, не выпив хотя бы одну бутылку
- проверять правильность введённого пароля, не получив хотя бы один пароль от пользователя
Представьте, что Вы просите у пользователя пароль, и затем сверяете его с базой данных. Операция очень дорогая (любое обращение к БД - это всегда "дорого", без исключений). 👇Если интересно почему - пишите вопрос в комментах. 👇 Обычный while выполняет проверку до ввода пользователем первого пароля, а значит - на первом цикле будет проверка корректности стартового пароля-пустышки.
let user = prompt_user(); let password = null; // не инициализированный пароль while (!check_password(password, user)) { // проверка пароля password = prompt_password(); }
👆как можно заметить, первый раз проверяется password, который равен null. Это не здорово.
Совсем другое дело, если мы будем использовать do-while:
let user = prompt_user(); let password = null; // не инициализированный пароль do { password = prompt_password(); } while (!check_password(password, user)) // проверка пароля
👆теперь пароль проверяется только после первого ввода. Это здорово и эффективно.
Цикл for
В программировании есть понятие "синтаксический сахар" - это конструкции, которые не привносят ничего нового, но они проще читаются. Цикл for - это синтаксический сахар для while с счетчиком.
Практическая задача: вам нужно почистить ровно N картофелин. Для этого Вы создаёте переменную count, в которой считаете число уже почищенных картофелин.
let count = 0; while (count < N) { take_new_potato(); clean_potato(); add_clean_potato_to_skovorodka(); count++; }
Что в таком коде плохого? Абсолютно ничего. Но всегда можно лучше 😎
Абсолютно тот же код, но с помощью for:
for (let count = 0; count < N; count++) { take_new_potato(); clean_potato(); add_clean_potato_to_skovorodka(); }
Чем такой код лучше? С точки зрения человека-программиста, в for явно видно начало и конец цикла, и не надо глазами искать строчки кода и сопоставлять их. Структура кода с помощью for читается лучше. Как ни странно, даже с точки зрения компьютера, такой код ему проще оптимизировать, так как он лучше понимает задумку автора.
Еще часто используется for для итерации по элементам в массиве. Но там тот же принцип - мы знаем число элементов в массиве, и перебираем значения счетчика от 0 до длины массива. Тот же счетчик. Не вижу смысла приводить отдельный пример.
Извращения с for
Читать уважаемым людям это не обязательно, но я должен упомянуть. У for есть только одно обязательное требование к синтаксису, что внутри скобок должны быть две точки с запятой. Что там ещё есть, или ничего нет - вообще никого не интересует. Например, могут быть пустые блоки начала и инкремента. Рассмотрим пример с чисткой картошки и while:
function skovorodka_is_full() { // здесь функция, которая определяет, заполнена ли сковородка } function have_potatoes() { // здесь функция, которая определяет, есть ли еще нечищенная картошка } for( ; ;!skovorodka_is_full() && have_potatoes()) { take_new_potato(); clean_potato(); add_clean_potato_to_skovorodka(); }
То есть, мы просто заменили while с помощью пустотелого for. Профит? Нет. Но я вижу такое гораздо чаще, чем корректное использование while, потому что программистам проще виртуозно овладеть одним словом, чем несколькими разными.
Заключение
while - если проверять условие надо до итерации
do-while - если проверять условие надо после итерации
for - синтаксический сахар для while, который придуман для упрощения случая с счетчиком итераций, но на самом деле все всегда используют только его :)