diff options
Diffstat (limited to 'files/ru/learn/javascript/building_blocks/looping_code/index.html')
-rw-r--r-- | files/ru/learn/javascript/building_blocks/looping_code/index.html | 936 |
1 files changed, 936 insertions, 0 deletions
diff --git a/files/ru/learn/javascript/building_blocks/looping_code/index.html b/files/ru/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..68f82b6d7b --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,936 @@ +--- +title: Зацикливание кода +slug: Learn/JavaScript/Building_blocks/Looping_code +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Языки программирования очень полезны для быстрой реализации повторяющихся задач. От базовых числовых операций до любой другой ситуации, когда у вас есть много похожих операций, которые нужно выполнить. В этой статье мы рассмотрим структуры циклов, доступные в JavaScript, которые можно использовать для этих целей.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Требования:</th> + <td>Базовые значения компьютерной системы и базовое понимаение HTML и CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript первые шаги</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять как работают циклы в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Циклы_в_коде">Циклы в коде</h2> + +<p>Циклы являются важной концепцией в программировании. Их использование основано на повторении одного и того же, что в программировании называется <strong>итерацией</strong>.</p> + +<p>Давайте рассмотрим работу фермера, который следит за тем, чтобы у него было достаточно еды, чтобы кормить всю свою семью в течении недели. Его работу можно представить в виде цикла:</p> + +<p><br> + <img alt="" src="https://mdn.mozillademos.org/files/13755/loop_js-02-farm.png" style="display: block; margin: 0 auto;"></p> + +<p>Цикл обычно составляет одну или несколько из следующих функций:</p> + +<ul> + <li> <strong>Счетчик</strong>, который инициализируется с определенного значения — начальной точки цикла (На рисунке выше первый этап: "у меня нет еды (i have no food)")</li> + <li><strong>Условие выхода </strong>— критерией, при котором цикл останавливается, — обычно наступает, когда цикл достигает определенного значения. Это иллюстрируется выше словами "Достаточно ли у меня еды? (Do I have enough food?)". Предположим, фермеру нужно 10 порций еды, чтобы прокормить семью.</li> + <li><strong>Итератор </strong>постепенно увеличивает счетчик на некоторое значение на каждом шаге цикла, пока не достигнуто условия выхода. Мы явно не показали это в изображении, но если предположить что фермер собирает две порции еды в час, то после каждого часа, количество еды, которое у него имеется, увеличивается на две порции, и он проверяет достаточно ли у него еды сейчас. Если у него собралось 10 порций (условие выхода), он может остановить сбор и вернуться домой.</li> +</ul> + +<p>В <a href="/ru/docs/Словарь/Pseudocode">псевдокоде</a> это будет выглядеть следующим образом:</p> + +<pre class="notranslate">loop(food = 0; foodNeeded = 10) { + if (food = foodNeeded) { + exit loop; + // У нас достаточно еды, пора домой + } else { + food += 2; // Прошел час, количество еды увеличилось на 2 + // переход на следующую итерацию цикла. + } +}</pre> + +<p>Таким образом, необходимое количество еды устанавливается равным 10, а изначально фермер не имеет ни одной порции, т.е. начало равно 0. На каждой итерации цикла проверяем, соответствует ли собранное количество еды, с тем количеством, которое ему необходимо. Если это так, можно выйти из цикла, если нет, фермер собирает еще 2 порции и снова переходит к проверке.</p> + +<h3 id="Зачем_это_нужно">Зачем это нужно?</h3> + +<p>Итак вы разобрались, как работают циклы. Но, вероятно, думаете: "Хорошо, но как это мне поможет писать код на JavaScript". Как мы писали ранее, <strong>циклы постоянно повторяют одно и тоже действие</strong>, что отлично подходит для <strong>быстрого выполнения повторяющихся задач</strong>.</p> + +<p>Часто код будет немного отличаться на каждой последующей итерации цикла. Это означает, что вы можете выполнять задачи, которые похожи, но у них есть некоторые различия. Например, если вам нужно выполнить много вычислений, немного отличающихся на каждой итерации.</p> + +<p>На следующем примере попробуем показать, почему циклы так полезны. Предположим мы хотели нарисовать 100 случайных кругов на элементе {{htmlelement("canvas")}}. Нажмите кнопку "Обновить", чтобы снова и снова запускать пример и увидеть, что круги рисуются случайным образом.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Random canvas circles</title> + <style> + html { + width: 100%; + height: inherit; + background: #ddd; + } + + canvas { + display: block; + } + + body { + margin: 0; + } + + button { + position: absolute; + top: 5px; + left: 5px; + } + </style> + </head> + <body> + + <button>Обновить</button> + + <canvas></canvas> + + + <script> + var btn = document.querySelector('button'); + var canvas = document.querySelector('canvas'); + var ctx = canvas.getContext('2d'); + + var WIDTH = document.documentElement.clientWidth; + var HEIGHT = document.documentElement.clientHeight; + + canvas.width = WIDTH; + canvas.height = HEIGHT; + + function random(number) { + return Math.floor(Math.random()*number); + } + + function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } + } + + btn.addEventListener('click',draw); + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 400) }}</p> + +<p>Вам необязательно понимать все части кода, но давайте посмотрим на место, где рисуются 100 кругов.</p> + +<pre class="brush: js notranslate">for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<ul> + <li><code>random()</code>, описанная в коде, возвращает случайное число между <code>0</code> и <code>x-1</code>.</li> + <li><code>WIDTH</code> и <code>HEIGHT</code> — это высота и ширина окна браузера.</li> +</ul> + +<p>Вы должны понять основную идею: мы используем цикл для запуска 100 итераций этого кода, каждая из которых рисует круг в случайном месте в окне. Количество кода было бы одинаковым, если бы нам нужно было нарисовать 10, 100 или 1000 кругов, поменяется лишь одно число.</p> + +<p>Если бы мы не использовали циклы, нам бы пришлось повторить следующий код, для отрисовки каждого круга:</p> + +<pre class="brush: js notranslate">ctx.beginPath(); +ctx.fillStyle = 'rgba(255,0,0,0.5)'; +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +ctx.fill();</pre> + +<p>Это множество лишнего кода очень усложнило бы подержку кода в будущем, т.к. если бы вам захотелось что-то изменить, в каждой итерации цикла, пришлось бы изменять все части кода по отдельности. А ещё это усложнаяет поиск ошибок, т.к. если вдруг вы совершите логическую ошибку при описании одной из итераций, придется потратить много времени на ее поиски.</p> + +<h2 id="Правила_записи_цикла">Правила записи цикла</h2> + +<p>Рассмотрим некоторые конкретные конструкции циклов. Первый вариант, который вы будете использовать чаще всего, это цикл <a href="/ru/docs/Web/JavaScript/Reference/Statements/for">for</a>. Он имеет следующий синтаксис:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // код для выполнения +}</pre> + +<p>Тут имеем:</p> + +<ol> + <li>Ключевое слово <a href="ru/docs/Web/JavaScript/Reference/Statements/for">for</a>, за которым следуют круглые скобки.</li> + <li>В круглых скобках у нас есть три части, разделенные точой с запятой: + <ol> + <li><strong>Инициализатор</strong> — обычно это переменная численного типа, которая увеличивается каждую итерацию, чтобы посчитать количество шагов цикла. Ее также называет <strong>счетчиком</strong>.</li> + <li><strong>Условие выхода</strong> — как упоминалось ранее, определяет, когда цикл должен остановиться. Обычно это выражение с оператором сравнения проверяющим, выполнено ли условие выхода.</li> + <li><strong>Окончательное выражение</strong> — вычисляется (или выполняется) каждый раз, когда цикл проходит полную итерацию. Обычно оно служит для увеличения (или уменьшения) переменной <strong>счетчика</strong>, чтобы приблизить ее значение к условию выхода.</li> + </ol> + </li> + <li>Фигурные скобки, содержащие блок кода. Этот код будет запускаться на каждой итерации цикла.</li> +</ol> + +<p>Посмотрим на пример, чтобы разобраться в этом более детально.</p> + +<pre class="brush: js notranslate">var cats = ['Билл', 'Макс', 'Пикси', 'Алиса', 'Жасмин']; +var info = 'Моих кошек зовут '; +var para = document.querySelector('p'); + +for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; +} + +para.textContent = info;</pre> + +<p>Этот блок кода будет иметь следующий результат:</p> + +<div class="hidden"> +<h6 id="Hidden_code_2">Hidden code 2</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Пример цикла For</title> + <style> + + </style> + </head> + <body> + + <p></p> + + + <script> + var cats = ['Билл', 'Макс', 'Пикси', 'Алиса', 'Жасмин']; + var info = 'Моих кошек зовут: '; + var para = document.querySelector('p'); + + for (var i = 0; i < cats.length; i++) { + info += cats[i] + ', '; + } + + para.textContent = info; + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60) }}</p> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">пример на GitHub</a> или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">посмотреть онлайн</a>.</p> +</div> + +<p>Здесь показан цикл, используемый для перебора элементов в массиве и выполнения определенных действий с каждым из них — очень распространенный шаблон в JavaScript<br> + Подробнее:</p> + +<ol> + <li>Итератор, <code>i</code>, начинается с <code>0</code> (<code>var i = 0</code>).</li> + <li>Цикл запускается, пока значение итератора не будет больше длины массива кошек. Это важно - условие выхода показывает когда именно цикл должен работать, а когда нужно выйти из цикла. Поэтому в случае, пока <code>i < cats.lenght</code> по-прежнему возвращает <code>true</code>, цикл будет работать.</li> + <li>Внутри тела цикла мы соединяем текущий элемент цикла (<code>cats[i]</code> это <code>cats</code>[независимо от того, чем <code>i</code> является в данный момент]) с запятой и пробелом. Итак: + <ol> + <li>В начале, <code>i = 0</code>, поэтому <code>cats[0] + ', '</code> соеденятся в ("Билл, ").</li> + <li>На втором шаге, <code>i = 1</code>, поэтому <code>cats[1] + ', '</code> соединятся в ("Макс, ")</li> + <li>И так далее. В конце каждого цикла <code>i</code> увеличится на 1 (<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">i++</span></font>) , и процесс будет начинаться заново.</li> + </ol> + </li> + <li>Когда <code>i</code> достигнет величины <code>cats.length</code> цикл остановится и браузер перейдет к следующему фрагменту кода после цикла.</li> +</ol> + +<div class="note"> +<p><strong>Заметка</strong>: Мы добавили условия выхода <code>i < cats.length</code>, а не <code>i <= cats.length</code>, потому что компьютеры считают с 0, а не с 1 — в начале <code>i = 0</code> и увеличивается до <code>i = 4</code> (индекс последнего элемента массива). <code>cats.length</code> возвращает 5, т.к. в массиве 5 элементов, но нам не нужно увеличивать до <code>i = 5</code>, т.к. <code>cats[5] </code>вернет <code>undefined</code> (в массиве нет элемента с индексом 5). Таким образом мы хотим придти к результату на 1 меньше, поэтому <code>i < cats.length</code>, не одно и тоже что <code>i <= cats.length</code>.</p> +</div> + +<div class="note"> +<p><strong>Заметка</strong>: Стандартной ошибкой с условием выхода является использование условия "равный" (<code>===</code>) ,а не "меньше или равно" (<code><=</code>). Если нам нужно увеличить счетчик до <code>i = 5</code>, условие выхода должно быть <code>i <= cats.length</code>. Если мы установим <code>i === cats.length</code>, цикл не начнется, т.к. <code>i</code> не равно <code>5</code> на самой первой итерации, поэтому цикл остановится сразу.</p> +</div> + +<p>Остается одна небольшая проблема: выходная строка сформирована не совсем корректно:</p> + +<blockquote> +<p>Моих кошек зовут Билл, Макс, Пикси, Алиса, Жасмин,</p> +</blockquote> + +<p>В идеале мы хотим изменить конкатенацию на последней итерации цикла так, чтобы у нас не было запятой в конце предложения. Для этого нужно добавить условное выражение внутрь цикла <code>for</code> для обработки этого особого случая:</p> + +<pre class="brush: js notranslate">for (var i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { + info += 'и ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } +}</pre> + +<div class="note"> +<p><strong>Заметка</strong>: Вы можете найти этот <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">пример на GitHub</a> или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">посмотреть онлайн</a>.</p> +</div> + +<div class="warning"> +<p><strong>Важно</strong>: С цкилом <strong>for</strong>, также как и сдругими циклами, вы должны убедиться что инициализатор (счетчик) и окончательное выражение построены так, что они достигнут условия выхода. Если этого не произойдет, то цикл будет продолжаться вечно. В итоге браузер или заставит его остановиться, или выдаст ошибку. Это называется <strong>бесконечным циклом</strong>.</p> +</div> + +<h2 id="Выход_из_цикла_с_помощью_break">Выход из цикла с помощью break</h2> + +<p>Если вы хотите выйти из цикла до завершения всех итераций, вы можете использовать оператор <a href="/ru/docs/Web/JavaScript/Reference/Statements/break">break</a> . Мы уже встречались с ним в предыдущей статье, когда рассматривали оператор <a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals#Оператор_switch">switch</a>: когда происходит событие, соответствующее условию, прописанному ключевым словом <code>case</code> внутри оператора <code>switch</code>, условие break моментально выходит из конструкции <code>switch</code> и запускает следующий после нее код.</p> + +<p>Тоже самое и с циклами — условие <code>break</code> моментально закончит цикл и заставит браузер запустить следующий после цикла код.</p> + +<p>Предположим, в массиве данных мы хотим найти имена контактов и телефонные номера, а вернуть только номер, который мы нашли.<br> + Начнем с разметки HTML: поле {{htmlelement("input")}} позволяет нам ввести имя для поиска, элемент (кнопка) {{htmlelement("button")}} для подтверждения поиска, и элемент {{htmlelement("p")}} для отображения результата:</p> + +<pre class="brush: html notranslate"><label for="search">Поиск по имени: </label> +<input id="search" type="text"> +<button>Поиск</button> + +<p></p></pre> + +<p>Теперь в JavaScript:</p> + +<pre class="brush: js notranslate">var contacts = ['Григорий:2232322', 'Марина:3453456', 'Василий:7654322', 'Наталья:9998769', 'Диана:9384975']; +var para = document.querySelector('p'); +var input = document.querySelector('input'); +var btn = document.querySelector('button'); + +btn.addEventListener('click', function() { + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + ', тел.: ' + splitContact[1] + '.'; + break; + } else { + para.textContent = 'Контакт не найден.'; + } + } +});</pre> + +<div class="hidden"> +<h6 id="Hidden_code_3">Hidden code 3</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple contact search example</title> + <style> + + </style> + </head> + <body> + + <label for="search">Найти имя контакта: </label> + <input id="search" type="text"> + <button>Поиск</button> + + <p></p> + + + <script> + var contacts = ['Григорий:2232322', 'Марина:3453456', 'Василий:7654322', 'Наталья:9998769', 'Диана:9384975']; + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + var searchName = input.value; + input.value = ''; + input.focus(); + for (var i = 0; i < contacts.length; i++) { + var splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + ', тел.: ' + splitContact[1] + '.'; + break; + } else if (i === contacts.length-1) + para.textContent = 'Контакт не найден.'; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100) }}</p> + +<ol> + <li>Прежде всего у нас определены некоторые переменные: у нас есть массив с контактной информацией, каждый элемент которого это строка, содержащая в себе имя и номер телефона, которые разделенны двоеточием.</li> + <li>Далее мы применяем обработчик события для кнопки (<code>btn</code>), чтобы при её нажатии запускался код для поиска и отображения результатов.</li> + <li>Мы сохраняем значение, введенное в текстовое поле, в переменную <code>searchName</code>, затем очищаем введеный текст и снова фокусируемся на текстовом поле для нового поиска.</li> + <li>Теперь перейдем к интересующей нас части — к циклу <code>for</code>: + <ol> + <li>Мы начали счетчик с <code>0</code>, запускаем цикл до тех пор, пока счетчик всё ещё меньше, чем contacts.length, а инкремент <code>i</code> увеличиваем на 1 после каждой иттерации цикла.</li> + <li>Внутри цикла мы сначала разделяем текущий контакт (<code>contacts[i]</code>) на символе двоеточия, и сохраняем полученные два значения в массиве с названием <code>splitContact</code>.</li> + <li>Затем мы используем условный оператор, чтобы проверить, равно ли <code>splitContact[0]</code> (имя контакта) введеному <code>searchName</code>. Если это так, мы выводим строку в абзац, чтобы сообщить, каков номер контакта, и используем <code>break</code> для завершения цикла.</li> + </ol> + </li> + <li> + <p>После <a href="https://ru.wikipedia.org/wiki/%D0%98%D1%82%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F_(%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F)">итерации</a> <code>(contacts.length-1)</code>, если имя контакта не совпадает с введенным именем в поисковом запросе, для текста абзаца устанавливается: «Контакт не найден.», и цикл продолжает повторяться.</p> + </li> +</ol> + +<div class="note"> +<p>Заметка: Вы можете посмотреть исходный код на <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">GitHub</a> или запустить его (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">see it running live</a>).</p> +</div> + +<h2 id="Пропуск_итераций_с_продолжением">Пропуск итераций с продолжением</h2> + +<p>Оператор <a href="/ru/docs/Web/JavaScript/Reference/Statements/continue">continue</a> работает аналогичным образом, как и <code>break</code>, но вместо полного выхода из цикла он переходит к следующей итерации цикла.</p> + +<p>Рассмотрим другой пример, в котором в качестве вводных данных принимается число, а возвращаются только числа, которые являются квадратами целых чисел.</p> + +<p>Код HTML в основном такой же, как и в предыдущем примере — простой ввод текста и абзац для вывода. JavaScript в основном такой же, хотя сам цикл немного другой:</p> + +<pre class="brush: js notranslate">var num = input.value; + +for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; +}</pre> + +<p>Вывод:</p> + +<div class="hidden"> +<h6 id="Hidden_code_4">Hidden code 4</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Генератор целочисленных квадратов</title> + <style> + + </style> + </head> + <body> + + <label for="number">Введите число: </label> + <input id="number" type="text"> + <button>Генерация целочисленных квадратов</button> + + <p>Результат: </p> + + + <script> + var para = document.querySelector('p'); + var input = document.querySelector('input'); + var btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + var num = input.value; + input.value = ''; + input.focus(); + para.textContent = 'Вы ввели: ' + num + '. Результат: '; + for (var i = 1; i <= num; i++) { + var sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100) }}</p> + +<ol> + <li>В этом случае на входе должно быть число (<code>num</code>). Циклу <code>for</code> присваивается счетчик, начинающийся с 1 (поскольку в данном случае нас не интересует 0), условие выхода, которое говорит, что цикл остановится, когда счетчик станет больше входного <code>num</code>, а итератор добавляет 1 к счетчику каждый раз.</li> + <li>Внутри цикла мы находим квадратный корень каждого числа с помощью <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt">Math.sqrt(i)</a>, а затем проверяем, является ли квадратный корень целым числом, проверяя, совпадает ли он с самим собой, когда он был округлен до ближайшего целого числа (это то, что <code>Math.floor ()</code> делает с числом, которое передает).</li> + <li>Если квадратный корень и округленный вниз квадратный корень не равны друг другу <code>(! ==)</code>, значит квадратный корень не является целым числом, поэтому нас он не интересует. В таком случае мы используем оператор <code>continue</code>, чтобы перейти к следующей итерации цикла без записи этого числа.</li> + <li>Если квадратный корень <em>является целым числом</em>, мы пропускаем блок <code>if</code> полностью, поэтому оператор <code>continue</code> не выполняется; вместо этого объединяется текущее значение <code>i</code> с пробелом в конце содержимого абзаца.</li> +</ol> + +<div class="note"> +<p><strong>Примечание. </strong>Вы также можете просмотреть полный исходный код на<strong> </strong><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html"> GitHub</a> (так же смотри <a href="https://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">этот код вживую</a>).</p> +</div> + +<h2 id="Циклы_while_и_do...while">Циклы <code>while</code> и <code>do...while</code></h2> + +<p><code><strong>for</strong> </code>— <code>не единственный тип цикла, доступный в JavaScript.</code> На самом деле существует множество других типов циклов. И хотя сейчас не обязательно знать их все, стоит взглянуть на структуру нескольких других, чтобы вы могли распознать те же функции, но в работе немного по-другому.</p> + +<p>Рассмотрим цикл <a href="/ru/docs/Web/JavaScript/Reference/Statements/while">while</a>. Синтаксис этого цикла выглядит так:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>Его действие очень похоже на цикл <code>for</code>, но переменная инициализатора устанавливается перед циклом, а заключительное выражение включается в цикл после запуска кода. Напомним, у цикла <code>for</code> эти два элемента заключены в круглых скобках. Здесь же после ключевого слова <code>while в круглых скобках заключено условие выхода из цикла.</code></p> + +<p>Здесь присутствуют те же три элемента и в том же порядке, что и в цикле <code>for</code>. Это важно, так как вам нужно определить инициализатор, прежде чем получится проверить, достиг ли цикл условия выхода.</p> + +<p>Окончательное условие выполняется после выполнения кода внутри цикла (итерация завершена), и оно выполняется только в том случае, если условие выхода еще не достигнуто.</p> + +<p>Посмотрим еще раз пример со списком кошек с кодом переписанным под использование цикла <code>while:</code></p> + +<pre class="brush: js notranslate">var i = 0; + +while (i < cats.length) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +}</pre> + +<div class="note"> +<p><strong>Примечание: </strong>цикл все еще работает так же, как и ожидалось - посмотрите, <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">как он работает на GitHub</a> (также посмотрите <a href="https://github.com/ConstantineZz/javaScript/blob/master/while.html">полный исходный код</a>).</p> +</div> + +<p>Цикл<strong> <a href="/ru/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a></strong> представляет собой вариацию структуры цикла <code>while</code>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>В этом случае инициализатор снова указывается прежде, чем цикл запускается. Ключевое слово <code>do</code> непосредственно предшествует фигурным скобкам, содержащим код для запуска и конечное выражение.</p> + +<p>Различие состоит в том, что условие выхода идет после всего остального, заключенное в скобки после ключевого слова <code>while</code>. В цикле <code>do...while</code> код внутри фигурных скобок всегда запускается один раз, прежде чем выполняется проверка, чтобы увидеть, должна ли она быть выполнена снова (в <code>while</code> и <code>for</code> проверка идет первой, поэтому код может быть не выполнен).</p> + +<p>Перепишем наш пример с кошками, чтобы использовать цикл <code>do...while</code>:</p> + +<pre class="brush: js notranslate">var i = 0; + +do { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +} while (i < cats.length);</pre> + +<div class="note"> +<p><strong>Примечание: </strong>И снова это работает так же, как и ожидалось - посмотрите, как он работает <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">на GitHub</a> (также посмотрите полный <a href="https://github.com/ConstantineZz/javaScript/blob/master/do-while.html">исходный код</a>).</p> +</div> + +<div class="warning"> +<p><strong>Замечание</strong>: Применяя циклы <code>while</code> and <code>do...while</code> , как и все циклы, убедитесь, что инициализатор повторяется так, чтобы он в конце концов достиг условия выхода. Если это не так, цикл будет продолжаться вечно, и либо браузер заставит его остановиться, либо произойдет сбой. Это называется <em><s>доктор Стрэндж и Дормамму</s></em> <strong>бесконечным циклом</strong>. </p> +</div> + +<h2 id="Практическое_упражнение_запускаем_обратный_отсчет!">Практическое упражнение: запускаем обратный отсчет!</h2> + +<p>В этом упражнении мы хотим, чтобы вы написали простой отсчет времени запуска до поля вывода, от 10 до "Пуск!" В частности, мы хотим, чтобы вы:</p> + +<ul> + <li>Цикл от 10 до 0. Мы предоставляем вам инициализатор: <code>var i = 10;</code>.</li> + <li>Для каждой итерации создайте новый абзац и добавьте его к выходному элементу <code><div></code>, который мы выбрали, используя <code>var output = document.querySelector ('.output');</code>. В комментариях мы предоставили вам три строки кода, которые необходимо использовать где-то внутри цикла: + <ul> + <li><code>var para = document.createElement('p');</code> — создать новый абзац.</li> + <li><code>output.appendChild(para);</code> — добавляет абзац к выводу <code><div></code>.</li> + <li><code>para.textContent =</code> — делает текст внутри абзаца равным значению, которое вы расположили справа, после знака равенства.</li> + </ul> + </li> + <li>Разные номера итераций требуют, чтобы в абзаце для каждой итерации помещался свой текст (вам понадобится условный оператор и несколько<code> para.textContent = lines</code><br> + ): + <ul> + <li>Если число равно 10, выведите в абзаце «Обратный отсчет 10».</li> + <li>Если число равно 0, выведите в абзаце «Пуск!»</li> + <li>Для любого другого числа выведите в абзаце только число.</li> + </ul> + </li> + <li>Не забудьте включить итератор! Однако в этом примере мы ведем обратный отсчет после каждой итерации, а не вверх, поэтому вам <strong>не</strong> нужен <code>i ++</code>. Как выполнить итерацию вниз?</li> +</ul> + +<p>Если вы допустили ошибку, вы всегда можете сбросить пример с помощью кнопки «Сброс» (Reset). Если у вас совсем ничего не получается, нажмите «Show solution», чтобы увидеть решение.</p> + +<div class="hidden"> +<h6 id="Active_learning">Active learning</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 410px;overflow: auto;"> + +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 300px;width: 95%"> +var output = document.querySelector('.output'); +output.innerHTML = ''; + +// var i = 10; + +// var para = document.createElement('p'); +// para.textContent = ; +// output.appendChild(para); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nvar i = 10;\n\nwhile(i >= 0) {\n var para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<p class="brush: js"></p> +</div> + +<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Практическое_упражнение_Заполнение_списка_гостей">Практическое упражнение: Заполнение списка гостей</h2> + +<p>Возьмите список имен, хранящихся в массиве, и поместите их в список гостей. Тут не всё так просто: мы не хотим приглашать Фила и Лолу, потому что они наглые и всё сожрут! У нас есть два списка. Один для тех, кого мы хотим пригласить, второй для тех, кого приглашать не нужно.</p> + +<p>Для этого нужно сделать следующее:</p> + +<ul> + <li>Напишите цикл, который будет повторяться от 0 до длины массива <code>people</code>.<br> + Вам нужно начать с инициализатора <code>var i = 0;</code> , но какое нужно использовать условие выхода?</li> + <li>Во время каждой итерации цикла нужно проверять, соответствует ли текущий элемент массива именам "Фил" или "Лола", используя условный оператор: + <ul> + <li>Если это так, привяжите этот элемент массива в конец <code>textContent</code> абзаца <code>refused</code>, за которым следуют запятая и пробел. </li> + <li>Если это не так, привяжите этот элемент массива в конец <code>textContent</code> абзаца <code>admitted</code>, за которым следуют запятая и пробел.</li> + </ul> + </li> +</ul> + +<p>Мы уже предоставили вам:</p> + +<ul> + <li><code>var i = 0;</code> — Ваш инициализатор.</li> + <li><code>refused.textContent +=</code> — начало строки, которая объединит что-то до конца <code>refused.textContent</code>.</li> + <li><code>admitted.textContent +=</code> — начало строки, которая объединит что-то до конца <code>admitted.textContent</code>.</li> +</ul> + +<p>Дополнительный бонусный вопрос - после успешного выполнения вышеупомянутых задач у вас останется два списка имен, разделенных запятыми, но они будут составлены некорректно: в конце каждого списка будет запятая. Сможете ли вы составить эти списки так, чтобы в конце каждой строки вместо запятой была точка. За помощью можно обратиться к статье «<a href="/ru/docs/Learn/JavaScript/Первые_шаги/Useful_string_methods">Полезные строковые методы</a>».</p> + +<p>Если вы допустили ошибку, вы всегда можете сбросить пример с помощью кнопки «Сброс» (Reset). Если у вас совсем ничего не получается, нажмите «Показать решение», чтобы увидеть решение.</p> + +<div class="hidden"> +<h6 id="Active_learning_2">Active learning 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 100px;overflow: auto;"> + <p class="admitted">Пригласить: </p> + <p class="refused">Не приглашать(!): </p> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +var people = ['Крис', 'Анна', 'Колин', 'Терри', 'Фил', 'Лола', 'Сем', 'Кай', 'Брюс']; + +var admitted = document.querySelector('.admitted'); +var refused = document.querySelector('.refused'); +admitted.textContent = 'Пригласить: '; +refused.textContent = 'Не приглашать(!): ' + +// var i = 0; + +// refused.textContent += ; +// admitted.textContent += ; + +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Показать решение'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Показать решение') { + textarea.value = solutionEntry; + solution.value = 'Скрыть решение'; + } else { + textarea.value = userEntry; + solution.value = 'Показать решение'; + } + updateCode(); +}); + +var jsSolution = 'var people = [\'Крис\', \'Анна\', \'Колин\', \'Терри\', \'Фил\', \'Лола\', \'Сем\', \'Кай\', \'Брюс\'];\n\nvar admitted = document.querySelector(\'.admitted\');\nvar refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Пригласить: \';\nrefused.textContent = \'Не приглашать(!): \'\nvar i = 0;\n\ndo {\n if(people[i] === \'Фил\' || people[i] === \'Лола\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680) }}</p> + +<h2 id="Так_какой_тип_цикла_использовать">Так какой тип цикла использовать?</h2> + +<p>В основном, используют <code>for</code>, <code>while</code> и <code>do...while</code> циклы, и они во многом взаимозаменяемы. Все они могут быть использованы для выполнения одних и тех же задач и какой из них вы будете использовать, во многом зависит от ваших личных предпочтений. Используйте тот, который вам проще всего запомнить или наиболее интуитивно понятен. Давайте вспомним каждый из них.</p> + +<p><strong><code>For</code></strong>:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><strong><code>while</code></strong>:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p><strong><code>do...while</code></strong>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>Для начала мы бы порекомендовали <code>for</code>, так как его проще запомнить: инициализатор, условие выхода и конечное выражение аккуратно заключено в скобки, поэтому их легко отследить, чтобы их не пропускать.</p> + +<div class="note"> +<p><strong>Примечание. </strong>Существуют и другие типы и функции цикла, которые полезны в сложных или специализированных ситуациях и выходят за рамки данной статьи. Если вы хотите подробнее изучить тему циклов, прочитайте наше расширенное<a href="/ru/docs/Web/JavaScript/Guide/Циклы_и_итерации"> руководство по циклам и итерациям.</a> </p> +</div> + +<h2 id="Заключение">Заключение</h2> + +<p>Эта статья раскрывает основные концепции и различные опции, доступные при циклическом кодировании в JavaScript. Теперь вам должно быть понятно, почему циклы являются хорошим механизмом для работы с повторяющимся кодом. Старайтесь использовать их в своих собственных примерах!</p> + +<p>Если вы чего-то не поняли, пробуйте читать статью снова или <a href="/ru/docs/Learn#Связаться_с_нами">свяжитесь с нами</a>, мы поможем разобраться.</p> + +<h2 id="Дополнительная_информация">Дополнительная информация</h2> + +<ul> + <li><a href="/ru/docs/Web/JavaScript/Guide/Циклы_и_итерации">Циклы и итерации</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/for">for свойства и характеристики</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/while">while</a> и <a href="/ru/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> описание</li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Statements/break">break</a> и <a href="/ru/docs/Web/JavaScript/Reference/Statements/continue">continue</a> описание</li> + <li> + <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — статья о практическом применении циклов</p> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></li> + <li><a href="/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> |