diff options
| author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
|---|---|---|
| committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
| commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
| tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/learn/javascript/building_blocks | |
| parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
| download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip | |
initial commit
Diffstat (limited to 'files/ru/learn/javascript/building_blocks')
9 files changed, 3410 insertions, 0 deletions
diff --git a/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html b/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..fab6711d39 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,254 @@ +--- +title: Создайте свою функцию +slug: Learn/JavaScript/Building_blocks/Build_your_own_function +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Эта статья призвана дать практический опыт на основе теоретических знаний приведенныйх в<a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions"> предыдущей статье</a>. Попутно мы также объясним некоторые важные детали работы с функциями.<br> + </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, <a href="/ru/docs/Learn/JavaScript/Первые_шаги">первые шаги в JavaScript</a>, <a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — блоки кода используемые многократно</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Научить создавать пользовательской функции и объяснить еще несколько полезных деталей.</td> + </tr> + </tbody> +</table> + +<h2 id="Активное_обучение_пострение_функции">Активное обучение: пострение функции</h2> + +<p>Пользовательская функция, которую мы собираемся построить, будет называться <code>displayMessage()</code>. Она отобразит настраиваемое окно сообщения на веб-странице и будет действовать как настраиваемая замена встроенной в браузер функции <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/alert">alert()</a>. Мы видели эту функцию раньше. Введите следующую команду в консоли JavaScript браузера на любой странице:</p> + +<pre class="brush: js">alert('This is a message');</pre> + +<p>Функция <code>alert</code> принимает один аргумент - строку, которая отображается в окне сообщения на веб-странице Попробуйте изменить строку, чтобы изменить сообщение.</p> + +<p>Функция <code>alert</code> ограничена: вы можете изменить текст сообщения, но не получится изменить его стиль, например, цвет, значок или что-то еще. Создадим сообщение, более интересное по стилю.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример будет работать во всех современных браузерах, но стиль может выглядеть немного смешным в более старых браузерах. Мы рекомендуем вам выполнять это упражнение в современном браузере, таком как Firefox, Opera или Chrome.</p> +</div> + +<h2 id="Основная_функция">Основная функция</h2> + +<p>Для начала давайте соберем основную функцию.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Для согласований имен функций нужно следовать тем же правилам, что и <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Variables#Правила_именования_переменных">правила именования переменных</a>. Отличить имена функций от имен переменных просто: после имен функций указываются круглые скобки, а после имен переменных их нет.</p> +</div> + +<ol> + <li>Откройте файл <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a> и скопируйте его себе на компьютер. Код HTML в нем предельно прост: body содержит только одну кнопку. Также здесь представлен базовый CSS для создания настраиваемого окна сообщений и пустой элемент {{htmlelement ("script")}} для размещения нашего JavaScript.</li> + <li>Затем добавьте строку внутри элемента <code><script></code>: + <pre class="brush: js">function displayMessage() { + +}</pre> + Мы начинаем с ключевого слова <code>function</code>, что означает, что мы определяем функцию. За ним следует имя, которое мы хотим дать нашей функции, набор круглых скобок и набор фигурных скобок. Любые параметры, которые мы хотим задать нашей функции, заключают в круглые скобки, а код, который запускается при вызове функции, находится внутри фигурных скобок.</li> + <li>Наконец, добавьте следующий код внутри фигурных скобок: + <pre class="brush: js">var html = document.querySelector('html'); + +var panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel); + +var msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +var closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn); + +closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + </li> +</ol> + +<p>Рассмотрим этот код по строкам (прим. - в оригинале статьи: "bit by bit").</p> + +<p>В первой строке используется функция DOM API под именем {{domxref ("document.querySelector()")}} для выбора элемента {{htmlelement ("html")}}, сохраняющая ссылку на него в переменной <code>html</code>, чтобы позже мы могли с ней что-то сделать:</p> + +<pre class="brush: js">var html = document.querySelector('html');</pre> + +<p>В следующем разделе используется другая функция DOM API, называемая {{domxref ("Document.createElement()")}}, применяется для создания элемента {{htmlelement ("div")}} и сохраняет ссылку на него в переменной, называемой <code>panel</code>. Этот элемент будет внешним контейнером нашего окна сообщений.</p> + +<p>Затем мы используем еще одну функцию DOM API, называемую {{domxref ("Element.setAttribute()")}}, чтобы установить атрибут <code>class</code> на нашей панели со значением <code>msgBox</code>. Это упрощает стилизацию элемента. Если вы посмотрите на CSS на странице, вы увидите, что мы используем селектор класса <code>.msgBox</code> для стилизации окна сообщения и его содержимого.</p> + +<p>Наконец, мы вызываем функцию DOM с именем {{domxref ("Node.appendChild()")}} в переменной <code>html</code>, которую мы сохранили ранее, которая вкладывает один элемент в другой как его дочерний элемент. Указываем панель <code><div></code> как дочерний элемент, который мы хотим вложить внутрь элемента <code><html></code>. То есть, когда мы создаем какой-то элемент, он не просто будет отображаться на странице сам по себе, нам нужно указать, куда его поместить.</p> + +<pre class="brush: js">var panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel);</pre> + +<p>В следующих двух разделах используются те же функции <code>createElement()</code> и <code>appendChild()</code>, которые мы уже видели, чтобы создать два новых элемента: {{htmlelement ("p")}} и {{htmlelement ("button")}}, и вставить их на страницу, как дочерних элементов панели <code><div></code>. Мы используем свойство {{domxref ("Node.textContent")}}, которое представляет текстовое содержимое элемента, для вставки сообщения внутри абзаца и символ «x» внутрь кнопки. Нажатие/активация этой кнопки будет закрывать окно сообщения.</p> + +<pre class="brush: js">var msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +var closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn);</pre> + +<p>В заключении мы используем обработчик событий {{domxref ("GlobalEventHandlers.onclick")}}, чтобы при нажатии кнопки был запущен некоторый код для удаления всей панели со страницы, т.е. для закрытия окна сообщения.</p> + +<p>Вкратце, обработчик <code>onclick</code> — это свойство, доступное для кнопки (или, фактически, для любого элемента страницы), которое можно установить в функцию, чтобы указать, какой код следует запускать при нажатии кнопки. Вы узнаете об этом больше в нашей статье о последующих событиях. Мы делаем обработчик <code>onclick</code> равным анонимной функции, которая содержит код, запускаемый при нажатии кнопки. Строка внутри функции использует функцию {{domxref ("Node.removeChild()")}} DOM API, чтобы указать, что мы хотим удалить определенный дочерний элемент внутри HTML — в данном случае панель <code><div></code>.</p> + +<pre class="brush: js">closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + +<p>В принципе, весь этот блок кода генерирует блок HTML, который выглядит так и вставляет его на страницу:</p> + +<pre class="brush: html"><div class="msgBox"> + <p>This is a message box</p> + <button>x</button> +</div></pre> + +<p>Вам не обязательно запоминать сейчас, как работает каждый элемент во всем этом коде. Основная задача — понять структуру и использование функции, при этом мы хотели показать что-то интересное для этого примера.</p> + +<h2 id="Вызов_функции">Вызов функции</h2> + +<p>Теперь у вас есть определение функции, написанное в вашем элементе <code><script></code>, но оно ничего не будет делать в том виде, в каком оно есть.</p> + +<ol> + <li>Попробуйте написать следующую строку под своей функцией, чтобы вызвать ее: + <pre class="brush: js">displayMessage();</pre> + Эта строка вызывает функцию, немедленно запуская ее. Когда вы сохраните код и перезагрузите его в браузере, вы увидите, что небольшое окно сообщения появляется сразу и только один раз.</li> + <li> + <p>Теперь откройте инструменты разработчика браузера на странице примера, перейдите в консоль JavaScript и снова введите эту строку. Вы увидите, что окно появится снова! Теперь у нас есть функция многократного использования, которую мы можем вызвать в любое время.</p> + + <p>Но мы, вероятно, хотим, чтобы оно появлялось в ответ на действия пользователя и системы. В реальном приложении такое окно сообщения, вероятно, будет вызвано в ответ на доступность новых данных или, если произошла ошибка, или, например, если пользователь пытаюется удалить свой профиль («вы уверены в этом?»), или если пользователь добавляет новый контакт и операция успешно завершена и т. д.</p> + + <p>В этой демонстрации мы получим окно сообщения, когда пользователь нажимает кнопку.</p> + </li> + <li>Удалите предыдущую добавленную строку.</li> + <li>Затем мы выберем кнопку и сохраним ссылку на нее в переменной. Добавьте следующую строку в свой код, над определением функции: + <pre class="brush: js">var btn = document.querySelector('button');</pre> + </li> + <li>Наконец, добавьте следующую строку ниже предыдущей: + <pre class="brush: js">btn.onclick = displayMessage;</pre> + Аналогично нашей строке <code>closeBtn.onclick...</code> внутри функции здесь мы вызываем некоторый код в ответ на нажатие кнопки. Но в этом случае вместо вызова анонимной функции, содержащей некоторый код, мы вызываем имя нашей функции напрямую.</li> + <li>Сохраните и обновите страницу. Теперь вы должны увидеть окно с сообщением, когда вы нажимаете кнопку.</li> +</ol> + +<p>Возможно, вам интересно, почему мы не включили круглые скобки после имени функции. Это связано с тем, что нам нужно не сразу вызвать функцию, а только после нажатия кнопки. Если вы попытаетесь изменить строку на</p> + +<pre class="brush: js">btn.onclick = displayMessage();</pre> + +<p>сохраните и перезагрузите страницу, вы увидите, что окно сообщения появляется без нажатия кнопки! Скобки в этом контексте иногда называют «оператором вызова функции». Вы используете их только в том случае, если хотите немедленно запустить функцию в текущей области. В этом же отношении код внутри анонимной функции не запускается сразу, так как он находится внутри области функций.</p> + +<p>Если вы пробовали последний эксперимент, перед тем, как продолжить, обязательно отмените последнее изменение.</p> + +<h2 id="Улучшение_функции_с_параметрами">Улучшение функции с параметрами</h2> + +<p>В нынешнем виде функция по-прежнему не очень полезна — мы не хотим показывать одно и то же сообщение по умолчанию каждый раз. Давайте улучшим нашу функцию, добавив некоторые параметры, позволяющие нам называть ее различными вариантами.</p> + +<ol> + <li> + <p>Прежде всего, обновите первую строку функции:</p> + + <pre class="brush: js">function displayMessage() {</pre> + + <p>к этому:</p> + + <pre class="brush: js">function displayMessage(msgText, msgType) {</pre> + Теперь, когда мы вызываем функцию, мы можем предоставить два значения переменных в круглых скобках, чтобы указать сообщение для отображения в окне сообщения, а также тип сообщения.</li> + <li>Чтобы использовать первый параметр, обновите следующую строку внутри своей функции: + <pre class="brush: js">msg.textContent = 'This is a message box';</pre> + + <p>к этому:</p> + + <pre class="brush: js">msg.textContent = msgText;</pre> + </li> + <li>И последнее, но не менее важное: теперь вам нужно обновить вызов функции, чтобы включить в него обновленный текст сообщения. Измените следующую строку: + <pre class="brush: js">btn.onclick = displayMessage;</pre> + + <p>к этому блоку:</p> + + <pre class="brush: js">btn.onclick = function() { + displayMessage('Woo, this is a different message!'); +};</pre> + Если мы хотим указать параметры в круглых скобках для вызываемой нами функции, то мы не можем назвать ее напрямую, нам нужно поместить ее в анонимную функцию, чтобы она не находилась непосредственно в области видимости и, следовательно, не вызывалась немедленно. Теперь она не будет вызываться до нажатия кнопки.</li> + <li>Перезагрузите и протестируйте код еще раз, и вы увидите, что он по-прежнему работает, только теперь вы также можете изменять сообщение внутри параметра, чтобы отображать разные сообщения в окне.</li> +</ol> + +<h3 id="Более_сложный_параметр">Более сложный параметр</h3> + +<p>Переход к следующему параметру. Это потребует немного больше работы. Установим его так, чтобы в зависимости от того, какой параметр <code>msgType</code> установлен, функция отображала другой значок и другой цвет фона.</p> + +<ol> + <li>Для начала, загрузите значки, необходимые для этого упражнения (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">warning</a> и <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">chat</a> [тут черные иконки на черном фоне... тролли на GitHub]) из GitHub. Сохраните их в новой папке <code>icons</code> в том же месте, что и ваш HTML-файл. + + <div class="note"><strong>Примечание</strong>: иконки <a href="https://www.iconfinder.com/icons/1031466/alarm_alert_error_warning_icon">warning</a> и <a href="https://www.iconfinder.com/icons/1031441/chat_message_text_icon">chat</a> были найдены на <a href="https://www.iconfinder.com/" rel="noopener">iconfinder.com</a>, и разработаны <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a>. Спасибо! (Фактические страницы значков были перемещены или удалены.) </div> + </li> + <li>Затем найдите CSS внутри вашего HTML-файла. Мы сделаем несколько изменений, чтобы освободить место для иконок. Во-первых, обновите ширину <code>.msgBox</code>: + <pre class="brush: css">width: 200px;</pre> + + <p>измените на:</p> + + <pre class="brush: css">width: 242px;</pre> + </li> + <li>Затем добавьте следующие строки в правило <code>.msgBox p { ... }</code> : + <pre class="brush: css">padding-left: 82px; +background-position: 25px center; +background-repeat: no-repeat;</pre> + </li> + <li>Теперь нам нужно добавить код в нашу функцию <code>displayMessage()</code>для обработки отображений значков. Добавьте следующий блок чуть выше закрывающей фигурной скобки "<code>}</code>" вашей функции: + <pre class="brush: js">if (msgType === 'warning') { + msg.style.backgroundImage = 'url(icons/warning.png)'; + panel.style.backgroundColor = 'red'; +} else if (msgType === 'chat') { + msg.style.backgroundImage = 'url(icons/chat.png)'; + panel.style.backgroundColor = 'aqua'; +} else { + msg.style.paddingLeft = '20px'; +}</pre> + Здесь, если параметр <code>msgType</code> установлен как <code>'warning'</code>, отображается значок предупреждения, а цвет фона панели устанавливается красным. Если для него установлено значение<code>'chat'</code>, отображается значок чата, а цвет фона панели становится голубым. Если параметр <code>msgType</code> не задан вообще (или задано что-то другое), тогда вступает в действие <code>else {...}</code>, а абзацу просто присваиваются заданные по умолчанию отступы, нет никакого значка, при этом не задается цвет фона окна сообщения. Это обеспечивает состояние по умолчанию, если не указан параметр <code>msgType</code>, что означает, что это необязательный параметр!</li> + <li>Давайте протестируем нашу обновленную функцию, попробуем обновить вызов displayMessage () из этого: + <pre class="brush: js">displayMessage('Woo, this is a different message!');</pre> + + <p>к одному из них:</p> + + <pre class="brush: js">displayMessage('Your inbox is almost full — delete some mails', 'warning'); +displayMessage('Brian: Hi there, how are you today?','chat');</pre> + Вот, насколько полезной становится наша (теперь не очень) маленькая функция.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Если у вас возникли проблемы с запуском примера, не стесняйтесь проверять свой код на готовой версии <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">GitHub</a> (см. также <a href="https://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">в режиме реального времени</a>) или обратитесь к нам за помощью.</p> +</div> + +<h2 id="Вывод">Вывод</h2> + +<p>В этой статье мы познакомились со всем процессом создания практической пользовательской функции, которую с небольшими доработками можно перенести в реальный проект. В следующей статье мы рассмотрим еще одну важную концепцию — возвращаемые значения функций.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p> + +<p> </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> + +<p> </p> diff --git a/files/ru/learn/javascript/building_blocks/conditionals/index.html b/files/ru/learn/javascript/building_blocks/conditionals/index.html new file mode 100644 index 0000000000..970c31d43b --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/conditionals/index.html @@ -0,0 +1,746 @@ +--- +title: Принятие решений в Вашем коде — условные конструкции +slug: Learn/JavaScript/Building_blocks/conditionals +tags: + - JavaScript + - Switch + - else + - if + - Для начинающих + - Операторы + - Статья +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Во многих языках программирования код должен иметь возможность принимать решения на основе введеных пользователем данных. Например, в игре, если у пользователя осталось 0 жизней, то игра завершается. В приложении о погоде утром отображается восход солнца, а вечером звезды и луна. В этой статье мы рассмотрим как в 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 first steps</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять принципы использования операторов условий в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Выбор_одного_условия!..">Выбор одного условия!..</h2> + +<p>Люди (и животные) принимают какие-либо решения всю жизнь, от малозначимых ("стоит ли мне съесть одну печеньку или две?") до жизнеопределяющих ("стоит ли мне остаться дома и работать на ферме отца или переехать в другую страну и изучать астрофизику?")</p> + +<p>Операторы условия в JavaScript позволяют нам указать разного рода действия в зависимости от выбранного пользователем или системой ответа (например одна печенька или две) и связать его с действием (результатом), например, результатом "съесть одну печеньку" будет "все еще буду чуствовать себя голодным", а результатом "съесть две печеньки" будет "буду чуствовать себя сытым, но мама меня наругает за то, что я съел все сладости". </p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="Оператор_if_..._else">Оператор if ... else</h2> + +<p>Давайте глянем на наиболее распространенный тип условного оператора, который вы будете использовать в JavaScript — <code><a href="/ru/docs/Web/JavaScript/Reference/Statements/if...else">if ... else</a></code><a href="/ru/docs/Web/JavaScript/Reference/Statements/if...else"> оператор</a>.</p> + +<h3 id="Базовый_if_..._else_синтаксис">Базовый if ... else синтаксис</h3> + +<p>Базовый <code>if...else</code> синтаксис выглядит как {{glossary("pseudocode")}}:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} else { + run some other code instead +}</pre> + +<p>Что мы имеем:</p> + +<ol> + <li>Ключевое слово <code>if</code> расположено перед круглыми скобками.</li> + <li>Условие для проверки (condition), расположено внутри круглых скобок (например "это значение больше другого значения?", или "это значение существует?"). Это условие использует операторы сравнения (<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">comparison operators</a>), которые мы изучим позже, и возвратит нам <code>true</code> или <code>false</code>.</li> + <li>Внутри скобок { } расположен код, который будет выполняться только в том случае, если условие (condition) верно (<code>true)</code>.</li> + <li>Ключевое слово <code>else (иначе)</code>.</li> + <li>Еще скобки { }, код внутри которых выполнится, только если условие не верно (не <code>true)</code>.</li> +</ol> + +<p>Этот код довольно читабелен — он говорит "<strong>if (если)</strong> <strong>condition (условие) </strong>возвращает <code>true (истина)</code>, запусти код A, <strong>else (иначе) </strong>запусти B"</p> + +<p>Стоит заметить, что <code>else</code> и второй блок скобок { } не обязателен — следующий код так же будет работать:</p> + +<pre class="notranslate">if (condition) { + код, который должен выполнить, если условие истина +} + +какой-то другой код</pre> + +<p>Тем не менее, следует быть осторожным — в случае, если код внутри вторых скобок { } не контролируется условием, то этот код будет выполняться <strong>всегда</strong>. Это не плохо, просто вы должны помнить об этом, чаще вы хотите запустить один кусок кода <em>или </em>другой, но не оба.</p> + +<p>И, наконец, иногда вы можете встретить код <code>if...else</code> без фигурных скобок в сокращенной форме:</p> + +<pre class="notranslate">if (condition) code to run if condition is true +else run some other code instead</pre> + +<p>Это абсолютно рабочий код, но он менее читаем, лучше использовать фигурные скобки, новые строки и отступы.</p> + +<h3 id="Реальный_пример">Реальный пример</h3> + +<p>Чтобы лучше понять синтаксис, давайте рассмотрим реальный пример. Представьте, что мать или отец попросили помочь с работой по дому своего ребенка. Родитель может сказать: "Если ты поможешь мне с покупками, то я дам тебе дополнительные деньги на карманные расходы, которые ты сможешь потратить на игрушку, какую захочешь". В JavaScript, мы можем представить это так: </p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone === true) { + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<p>В этом коде, как показано, всегда будет <code>shoppingDone</code> равный <code>false</code>, что означает разочарование для нашего бедного ребенка. Мы должны предоставить механизм для родителя, чтобы установить для переменной <code>shoppingDone</code> значение <code>true</code> , если ребенок помог с покупками.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете увидеть больше в <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">полной версии этого примера на GitHub</a> (также посмотреть как он <a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">работает вживую</a>.)</p> +</div> + +<h3 id="else_if">else if</h3> + +<p>В предыдущем примере предоставлено два выбора, или результата — но что, если мы хотим больше, чем два?</p> + +<p>Существует способ привязать дополнительные варианты/результаты к вашему <code>if...else</code> — использовать<code>else if</code>. Для каждого дополнительного выбора требуется дополнительный блок, который нужно расположить между <code>if() { ... }</code> и <code>else { ... }</code> — проверьте следующий более сложный пример, который может быть частью простого приложения прогноза погоды:</p> + +<pre class="brush: html notranslate"><label for="weather">Выберите тип погоды сегодня: </label> +<select id="weather"> + <option value="">--Сделайте выбор--</option> + <option value="sunny">Солнечно</option> + <option value="rainy">Дождливо</option> + <option value="snowing">Снежно</option> + <option value="overcast">Облачно</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + +function setWeather() { + var choice = select.value; + + if (choice === 'sunny') { + para.textContent = 'Сегодня хорошо и солнечно. Носите шорты! Идите на пляж, или в парк, и купите мороженое.'; + } else if (choice === 'rainy') { + para.textContent = 'Дождь падает за окном; возьмите плащ и зонт, и не находитесь слишком долго на улице.'; + } else if (choice === 'snowing') { + para.textContent = 'Снег падает - морозно! Лучше всего посидеть с чашкой горячего шоколада или слепить снеговика.'; + } else if (choice === 'overcast') { + para.textContent = 'Дождя нет, но небо серое и мрачное; он все может измениться в любую минуту, поэтому на всякий случай возьмите дождевик.'; + } else { + para.textContent = ''; + } +} + +</pre> + +<p>{{ EmbedLiveSample('else_if', '100%', 100) }}</p> + +<ol> + <li>Здесь у нас есть элемент HTML {{htmlelement("select")}} который позволяет нам выбирать разные варианты погоды и простой абзац.</li> + <li>В JavaScript, мы создаем ссылки на элементы {{htmlelement("select")}} и {{htmlelement("p")}}, и добавляем обработчик события для элемента <code><select></code> , чтобы при изменении его значения, запускалась функция <code>setWeather()</code>.</li> + <li>Когда функция будет запущена, первоначально мы определим значение переменной <code>choice</code>, которая равна выбранному значению в элементе <code><select></code>. Затем мы используем условный оператор для отображения текста внутри абзаца в зависимости от того, какое значение у переменной <code>choice</code>. Обратите внимание, как все условия проверяются в <code>else if() {...}</code> блоках, за исключением первого, который использует <code>if() {...}</code>блок.</li> + <li>Последний выбор, внутри <code>else {...}</code> блока, в основном является «последним средством» — код внутри него будет запущен, если ни одно из условий не будет <code>true</code>. В этом случае он служит для удаления текста из абзаца, если ничего не выбрано, например, если пользователь решает повторно выбрать опцию "--Сделайте выбор--" которая указана в начале.</li> +</ol> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">найти этот пример на GitHub</a> (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">увидеть как он работает</a>)</p> +</div> + +<h3 id="Примечание_об_операторах_сравнения">Примечание об операторах сравнения</h3> + +<p>Операторы сравнения используют для проверки условий внутри наших условных операторов. Сначала мы посмотрели на операторы сравнения в нашей статье <a href="/ru/docs/Learn/JavaScript/Первые_шаги/Math#Comparison_operators">Базовая математика в JavaScript — цифры и операторы</a> . Наш выбор это:</p> + +<ul> + <li><code>===</code> и <code>!==</code> — проверяет одно значение идентично или не идентично другому.</li> + <li><code><</code> и <code>></code> — проверяет одно значение меньше или больше, чем другое.</li> + <li><code><=</code> и <code>>=</code> — проверяет одно значение меньше или равно, либо больше или равно другому.</li> +</ul> + +<div class="note"> +<p><strong>Примечание</strong>: Просмотрите материал по предыдущей ссылке, если вы хотите освежить свою память.</p> +</div> + +<p>Мы хотели бы особо обратить внимание на проверку булевых значений (<code>true</code>/<code>false</code>), и общий шаблон, который вы будете встречать снова и снова. Любое значение, которое не есть <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code>, или пустая строка (<code>''</code>) фактически возвращает <code>true</code> при тестировании как условного оператора. Поэтому вы можете просто использовать имя собственной переменной, чтобы проверить, равна ли она <code>true</code>, или существует (т. е. переменная не равна undefined). Например:</p> + +<pre class="brush: js notranslate">var cheese = 'Cheddar'; + +if (cheese) { + console.log('Ура! Есть сыр для приготовления бутерброда.'); +} else { + console.log('Сегодня нет сыра для бутерброда.'); +}</pre> + +<p>И, возвращаясь к нашему предыдущему примеру о ребенке, выполняющем поручение своего родителя, вы можете это записать так:</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone) { // не нужно явно указывать '=== true' + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<h3 id="Вложенность_if_..._else">Вложенность if ... else</h3> + +<p>Вполне нормально использовать один условный оператор <code>if...else</code> внутри другого — вложить их. Например, мы могли бы обновить наше приложение прогноза погоды, чтобы показать еще один набор вариантов в зависимости от температуры:</p> + +<pre class="brush: js notranslate">if (choice === 'sunny') { + if (temperature < 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — хорошо и солнечно. Идите на пляж, или в парк, и купите мороженое.'; + } else if (temperature >= 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — Жара! Если вы хотите выйти на улицу, обязательно используйте солнцезащитный крем.'; + } +}</pre> + +<p>Несмотря на то, что весь код работает вместе, каждый условный оператор <code>if...else</code> работает полностью отдельно от другого.</p> + +<h3 id="Логические_операторы_И_ИЛИ_и_НЕ">Логические операторы: И, ИЛИ и НЕ</h3> + +<p>Если Вы хотите проверить несколько условий без записи вложенных <code>if...else</code> условий, <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">логические операторы</a> помогут Вам. При использовании в условиях, первые два оператора делают следующее:</p> + +<ul> + <li><code>&&</code> — И; позволяет объединить два или более выражения так, что каждое из них отдельно должно иметь значение <code>true</code> , чтобы в итоге общее выражение имело значение <code>true</code>.</li> + <li><code>||</code> — ИЛИ; позволяет объединить два или более выражения так, что одно или несколько из них должно иметь значение <code>true</code> , чтобы в итоге общее выражение имело значение<code>true</code>.</li> +</ul> + +<p>Чтобы дать вам пример оператора И, предыдущий фрагмент кода можно переписать так:</p> + +<pre class="brush: js notranslate">if (choice === 'sunny' && temperature < 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — хорошо и солнечно. Идите на пляж, или в парк, и купите мороженое.'; +} else if (choice === 'sunny' && temperature >= 86) { + para.textContent = 'Сейчас ' + temperature + ' градусов по фаренгейту — Жара! Если вы хотите выйти на улицу, обязательно используйте солнцезащитный крем.'; +}</pre> + +<p>Так, для примера, первый блок кода выполнится только в том случае, если <code>choice === 'sunny'</code> <em>и</em><code>temperature < 86</code> вернут значение <code>true</code>.</p> + +<p>Давайте посмотрим на быстрый пример оператора ИЛИ:</p> + +<pre class="brush: js notranslate">if (iceCreamVanOutside || houseStatus === 'в огне') { + //если подъехал фургон с мороженым или дом горит + console.log('Вы должны быстро покинуть дом.'); +} else { + console.log('Вероятно, можно в нем оставаться.'); +}</pre> + +<p>Последний тип логического оператора НЕ, выраженный <code>!</code> оператором, можно использовать для отрицания выражения. Давайте объединим его с ИЛИ в приведенном выше примере:</p> + +<pre class="brush: js notranslate">if (!(iceCreamVanOutside || houseStatus === 'on fire')) { + console.log('Вероятно, можно в нем оставаться.'); +} else { + console.log('Вы должны быстро покинуть дом.'); +}</pre> + +<p>В этом фрагменте, если условие ИЛИ возвращает <code>true</code>, оператор НЕ будет отрицать это и выражение вернет <code>false</code>.</p> + +<p>Можно сочетать любое количество логических операторов, в любой последовательности и в любой комбинации. В следующем примере код в блоке будет выполняться только в том случае, если оба условия с ИЛИ возвращают true, а следовательно, и оператор И возвращает true:</p> + +<pre class="brush: js notranslate">if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { + // код выполняется +}</pre> + +<p>Распространенной ошибкой при использовании логического оператора ИЛИ в условном выражении является указание переменной, значение которой нужно проверить со списком возможных значений этой переменной, разделенных операторами <code>||</code> (ИЛИ). Например.</p> + +<pre class="example-bad brush: js notranslate">if (x === 5 || 7 || 10 || 20) { + // выполнить код +}</pre> + +<p>В данном примере условие в <code>if(...)</code> всегда будет оцениваться как true, поскольку 7 (или любое другое ненулевое значение) всегда будет оцениваться как true. Фактически, это условие гласит «если х равен 5, или 7 является true». Но нам требуется совсем не это. Чтобы достичь нужной цели, придется выполнять полноценную проверку после каждого оператора ИЛИ:</p> + +<pre class="brush: js notranslate">if (x === 5 || x === 7 || x === 10 ||x === 20) { + // выполнить код +}</pre> + +<h2 id="Оператор_switch">Оператор switch</h2> + +<p>Выражения <code>if...else</code> отлично справляются с добавлением условного кода, однако они не лишены недостатков. Они хорошо подходят для ситуации, когда имеется всего пара вариантов развития событий, каждый из которых имеет блок с приемлемым количеством кода, а также в случаях, когда условие является довольно сложным и включает несколько логических операторов. Если же нам требуется всего лишь задать переменную для определенного выбранного значения или напечатать конкретную фразу при определенном условии, изученный нами синтаксис может оказаться довольно громоздким, особенно если имеется большое количество вариантов выбора.</p> + +<p>В этом случае нам поможет <a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch">оператор <code>switch</code> </a>– он принимает одно единственное выражение или значение, а затем просматривает ряд вариантов, пока не найдут вариант, соответствующий этому значению, после чего выполняет код, назначенный этому варианту. Вот пример использования этого оператора:</p> + +<pre class="notranslate">switch (выражение) { + case choice1: + выполнить этот код + break; + + case choice2: + выполнить этот код, а не предыдущий + break; + + // вариантов может быть любое количество + + default: + а вообще-то, выполнить только этот код +}</pre> + +<p>Что мы имеем:</p> + +<ol> + <li>Ключевое слово <code>switch</code>, за которым следует пара круглых скобок.</li> + <li>В скобках приводится выражение или значение.</li> + <li>Ключевое слово <code>case</code>, за которым следует вариант выбора (именно он проверяется на соответствие выражению или значению) и двоеточие.</li> + <li>Код, который будет выполняться, если вариант совпадает с выражением.</li> + <li>Оператор <code>break</code>, за которым следует точка с запятой. Если вариант совпал с выражением или значением, браузер закончит выполнять блок кода, дойдя до оператора <code>break</code>, и перейдет к выполнению кода, расположенного после оператора switch.</li> + <li>Вариантов выбора (пункты 3–5) может быть сколь угодно много.</li> + <li>Ключевое слово <code>default</code> используется точно также, как любой другой вариант выбора (пункты 3–5) за тем исключением, что после <code>default</code> нет других вариантов выбора, поэтому инструкция <code>break</code> не требуется, никакого кода дальше нет. Это вариант выбора по умолчанию, выбираемый, если ни один из других вариантов не совпал с выражением.</li> +</ol> + +<div class="note"> +<p><strong>Примечание.</strong> Вариант выбора <code>default</code> может быть пропущен, если выражение гарантированно совпадет с одним из вариантов выбора. В противном случае вариант <code>default</code> необходим.</p> +</div> + +<h3 id="Пример_оператора_switch">Пример оператора switch</h3> + +<p>Давайте рассмотрим реальный пример — перепишем наше приложение прогноза погоды с использованием оператора switch:</p> + +<pre class="brush: html notranslate"><label for="weather">Выберите тип погоды сегодня: </label> +<select id="weather"> + <option value="">--Сделайте выбор--</option> + <option value="sunny">Солнечно</option> + <option value="rainy">Дождливо</option> + <option value="snowing">Снежно</option> + <option value="overcast">Облачно</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + + +function setWeather() { + var choice = select.value; + + switch (choice) { + case 'sunny': + para.textContent = 'Сегодня хорошо и солнечно. Наденьте шорты! Идите на пляж или в парк, и купите мороженое.'; + break; + case 'rainy': + para.textContent = 'На улице дождь. Возьмите плащ и зонт, и не гуляйте слишком долго'; + break; + case 'snowing': + para.textContent = 'Идет снег - морозно! Лучше всего посидеть с чашкой горячего шоколада или слепить снеговика.'; + break; + case 'overcast': + para.textContent = 'Дождя нет, но небо серое и мрачное; он все может измениться в любую минуту, поэтому на всякий случай возьмите дождевик.'; + break; + default: + para.textContent = ''; + } +}</pre> + +<p>{{ EmbedLiveSample('Пример_оператора_switch', '100%', 100) }}</p> + +<div class="note"> +<p><strong>Note</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">найти этот пример на GitHub</a> (также увидеть <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">как он работает</a>.)</p> +</div> + +<h2 id="Тернарный_оператор">Тернарный оператор</h2> + +<p>Это последний теоретический раздел данной статьи и мы перейдем к практическим упражнениям. <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Тернарный или условный оператор</a> имеет простой синтаксис: он проверяет условие и возвращает одно значение или выражение, если условие является <code>true</code>, и другое значение/выражение, если условие является <code>false</code>. Часто это очень удобная альтернатива блоку <code>if...else</code>, позволяющая затрачивать меньшие усилия на написание кода, когда имеется всего лишь два варианта, выбираемых на основе условия <code>true</code>/<code>false</code>. Общая схема оператора:</p> + +<pre class="notranslate">( условие) ? выполнить этот код : выполнить этот код вместо первого</pre> + +<p>Приведем простой пример:</p> + +<pre class="brush: js notranslate">var greeting = ( isBirthday ) ? 'С днем рождения, г-н Кузнецов! Хорошо Вам повеселиться!' : 'Доброе утро, г-н Кузнецов.';</pre> + +<p>У нас есть переменная <code>isBirthday</code> , если она <code>true</code>, мы отправляем посетителю поздравление с днем рождения; если нет – выдаем стандартное приветствие.</p> + +<h3 id="Пример_тернарного_оператора">Пример тернарного оператора</h3> + +<p>При использовании тернарного оператора не обязательно ограничиваться лишь значениями переменной, можно выполнять функции или строки кода; все, что угодно. В следующем примере показано простое средство выбора темы, задающее внешний вид веб-сайта с помощью тернарного оператора.</p> + +<pre class="brush: html notranslate"><label for="theme">Выберите тему: </label> +<select id="theme"> + <option value="white">Белая</option> + <option value="black">Черная</option> +</select> + +<h1>Это мой веб-сайт</h1></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var html = document.querySelector('html'); +document.body.style.padding = '10px'; + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +} + +select.onchange = function() { + ( select.value === 'black' ) ? update('black','white') : update('white','black'); +} +</pre> + +<p>{{ EmbedLiveSample('Пример_тернарного_оператора', '100%', 300) }}</p> + +<p>Мы используем элемент {{htmlelement('select')}} для выбора темы (черная или белая), а также простой {{htmlelement('h1')}} для отображения заголовка веб-сайта. Кроме того, у нас есть функция <code>update()</code>, принимающая в качестве параметров (входных данных) два цвета. В качестве фона используется первый переданный цвет, а в качестве цвета текста – второй переданный цвет.</p> + +<p>Наконец, у нас есть слушатель событий <a href="/en-US/docs/Web/API/GlobalEventHandlers/onchange">onchange</a> , использующийся для запуска функции, содержащей тернарный оператор. Сначала она проверяет условие — <code>select.value === 'black'</code>. Если возвращается <code>true</code>, мы запускаем функцию <code>update()</code> с параметрами черного и белого, в результате чего получаем черный цвет фона и белый цвет текста. Если возвращается <code>false</code>, мы запускаем функцию <code>update()</code> с параметрами белого и черного, в результате чего цвета веб-сайта меняются на противоположные.</p> + +<div class="note"> +<p><strong>Note</strong>: Вы можете <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">найти этот пример на GitHub</a> (также увидеть <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">как он работает</a>.)</p> +</div> + +<h2 id="Практическое_упражнение_простой_календарь">Практическое упражнение: простой календарь</h2> + +<p>В данном примере вы поможете нам закончить простое приложение календаря. Код включает:</p> + +<ul> + <li>Элемент {{htmlelement("select")}}, позволяющий пользователю выбирать разные месяцы.</li> + <li>Обработчик событий <code>onchange</code> для обнаружения изменения значения, выбранного в меню <code><select></code>.</li> + <li>Функция <code>createCalendar()</code> , рисующая календарь и отображающая правильный месяц в элементе {{htmlelement("h1")}}.</li> +</ul> + +<p>Вы должны написать условную конструкцию в функции обработчика <code>onchange</code> , сразу после комментария <code>// ДОБАВЬТЕ СЮДА УСЛОВНОЕ ВЫРАЖЕНИЕ</code>. Конструкция должна:</p> + +<ol> + <li>Проверить выбранный месяц (хранящийся в переменной <code>choice</code>. Это будет значение элемента <code><select></code> после изменения значения, например, "Январь".)</li> + <li>Задать переменную, скажем, <code>days</code>, равную количеству дней в выбранном месяце. Для этого нужно будет проверить количество дней в каждом месяце. Високосный год можно не учитывать.</li> +</ol> + +<p>Советы:</p> + +<ul> + <li>Советуем использовать логический оператор OR для группировки нескольких месяцев в рамках одного условия; многие месяцы имеют одинаковое количество дней.</li> + <li>Подумайте, какое количество дней в месяце встречается чаще всего и используйте его в качестве варианта по умолчанию.</li> +</ul> + +<p>Если допустили ошибку, используйте кнопку «Сброс», чтобы вернуться к исходному виду примера. Если у вас совсем ничего не получается, нажмите «Показать решение».</p> + +<div class="blockIndicator note"> +<p>В HTML коде внутри <code><select></code> названия месяцев <code>value=""</code> введены на русском языке. Соответственно ссылки на них из вашего скрипта так же на русском. Не забываем про синтаксис. (прим. - <a href="/ru/profiles/ConstantineZz">ConstantineZz</a>)</p> +</div> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 500px;overflow: auto;"> +<label for="month">Выберите месяц: </label> +<select id="month"> +<option value="Январь">Январь</option> +<option value="Февраль">Февраль</option> +<option value="Март">Март</option> +<option value="Апрель">Апрель</option> +<option value="Май">Май</option> +<option value="Июнь">Июнь</option> +<option value="Июль">Июль</option> +<option value="Август">Август</option> +<option value="Сентябрь">Сентябрь</option> +<option value="Октябрь">Октябрь</option> +<option value="Ноябрь">Ноябрь</option> +<option value="Декабрь">Декабрь</option> +</select> +<h1></h1> +<ul></ul> </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 select = document.querySelector('select'); +var list = document.querySelector('ul'); +var h1 = document.querySelector('h1'); + +select.onchange = function() { + var choice = select.value; + + // <code>ДОБАВЬТЕ СЮДА УСЛОВНОЕ ВЫРАЖЕНИЕ</code> + + createCalendar(days, choice); +} + +function createCalendar(days, choice) { + list.innerHTML = ''; + h1.textContent = choice; + for (var i = 1; i <= days; i++) { + var listItem = document.createElement('li'); + listItem.textContent = i; + list.appendChild(listItem); + } +} + +createCalendar(31,'Январь'); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div></pre> + +<pre class="brush: css notranslate">.output * { + box-sizing: border-box; +} + +.output ul { + padding-left: 0; +} + +.output li { + display: block; + float: left; + width: 25%; + border: 2px solid white; + padding: 5px; + height: 40px; + background-color: #4A2DB6; + color: white; +} + +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 select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'Февраль\') {\n days = 28;\n } else if(choice === \'Апрель\' || choice === \'Июнь\' || choice === \'Сентябрь\'|| choice === \'Ноябрь\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i <= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'Январь\');'; +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 === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 1110) }}</p> + +<h2 id="Практическое_упражнение_расширяем_выбор_цветов">Практическое упражнение: расширяем выбор цветов</h2> + +<p>В данном примере вы будете использовать пример тернарного оператора, который мы рассматривали ранее, и превратите тернарный оператор в инструкцию switch, что позволит увеличить количество вариантов выбора для простого веб-сайта. Посмотрите на {{htmlelement("select")}} — на этот раз он включает не два, а целых пять вариантов тем. Нужно добавить инструкцию switch сразу под комментарием <code>// ДОБАВЬТЕ ИНСТРУКЦИЮ SWITCH</code>:</p> + +<ul> + <li>Она должна принимать переменную <code>choice</code> в качестве входного выражения.</li> + <li>Каждый элемент case должен содержать вариант выбора, соответствующий одному из доступных для выбора значений: белая, черная, лиловая, желтая или психоделическая тема.</li> + <li>В блоке каждого элемента case необходимо вызывать функцию <code>update()</code>, которой передается два цвета: первый – это цвет фона, а второй – цвет текста. Помните, что значения цветов – это строковые значения, поэтому их нужно заключать в кавычки.</li> +</ul> + +<p>Если допустили ошибку, используйте кнопку «Сброс», чтобы вернуться к исходному виду примера. Если у вас совсем ничего не получается, нажмите «Показать решение».</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><div class="output" style="height: 300px;"> + <label for="theme">Выберите тему: </label> + <select id="theme"> + <option value="white">Белая</option> + <option value="black">Черная</option> + <option value="purple">Лиловая</option> + <option value="yellow">Желтая</option> + <option value="psychedelic">Психоделическая</option> + </select> + + <h1>Это мой веб-сайт</h1> +</div> + +<hr> + +<textarea id="code" class="playable-code" style="height: 450px;"> +var select = document.querySelector('select'); +var html = document.querySelector('.output'); + +select.onchange = function() { + var choice = select.value; + + // ДОБАВЬТЕ ИНСТРУКЦИЮ SWITCH +} + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +}</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Сброс"> + <input id="solution" type="button" value="Показать решение"> +</div> +</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; + +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 select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\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 === 'Показать решение') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + +updateCode(); + +}; + +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 650) }}</p> + +<h2 id="Заключение">Заключение</h2> + +<p>Это все, что вам нужно знать на данный момент об условных логических структурах! Уверены, вы хорошо разобрались в теоретическом материале и с легкостью справились с предложенными упражнениями. Если же что-то осталось для вас непонятным, перечитайте статью еще раз или <a href="/en-US/Learn#Contact_us">свяжитесь с нами</a>.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Comparison operators</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements">Conditional statements in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if...else reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Conditional (ternary) operator reference</a></li> +</ul> + +<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/ru/learn/javascript/building_blocks/functions/index.html b/files/ru/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..b612858b42 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,390 @@ +--- +title: Функции — Переиспользуемые блоки кода +slug: Learn/JavaScript/Building_blocks/Functions +tags: + - Функции + - аргументы + - методы + - параметры +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Другая важная концепция в кодировании — <strong>функции </strong>— позволяют хранить фрагмент кода, который выполняет одну задачу внутри определенного блока, а затем вызывать этот код всякий раз, когда вам это нужно, используя одну короткую команду, вместо того, чтобы вводить один и тот же код несколько раз.</p> + +<p class="summary">В этой статье мы рассмотрим фундаментальные концепции функций, такие как базовый синтаксис, способы вызова и их определения, область действия и параметры.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Начальная компьютерная грамотность, основы HTML и CSS, <a href="/ru/docs/Learn/JavaScript/First_steps">первые шаги JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Понять фундаментальные основы функций языка JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Где_можно_встретить_функции">Где можно встретить функции?</h2> + +<p>В JavaScript, Вы везде уведите функции. На самом деле, мы пользовались функциями на протяжении всего курса; только мы не говорили об этом слишком часто. Теперь наступило время, чтобы поговорить о функциях более конкретно и разобрать их синтаксис.</p> + +<p>В значительном количестве случаев, когда вы пользуетесь структурой JavaScript, в которой есть пара обычных скобок — <code>()</code> — и при этом, это не является структурой типа <a href="/ru/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">цикл for </a>, <a href="/ru/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">while, или do...while цикл</a>, или <a href="/ru/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">if...else конструкция</a>, Вы используете функцию.</p> + +<h2 id="Встроенные_функции_браузера">Встроенные функции браузера</h2> + +<p>В этом курсе мы использовали функции, встроенные в браузер. Каждый раз, когда мы манипулировали текстовой строкой, например:</p> + +<pre class="brush: js notranslate">var myText = 'Я строка'; +var newString = myText.replace('строка', 'сосиска'); +console.log(newString); +// Функция строки replace() принимает строку, +// заменяет одну строку на другую, и возвращает +// новую строку с замененным содержимым</pre> + +<p>Или каждый раз, когда мы манипулировали массивом:</p> + +<pre class="brush: js notranslate">var myArray = ['Я', 'люблю', 'шоколадных', 'лягушек']; +var madeAString = myArray.join(' '); +console.log(madeAString); +// Функция join() принимает массив, соединяет +// все элементы массива вместе в одну строку, +// и возвращает эту новую строку</pre> + +<p>Или каждый раз, когда мы генерировали случайное число:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random() +// Функция random() генерирует случайное число от 0 до 1, +// и возвращает это число</pre> + +<p>...мы использовали функции!</p> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете вставить эти строки в консоль вашего браузера, чтобы посмотреть, как работают эти функции.</p> +</div> + +<p>Фактически, часть кода, который вы вызываете, когда ссылаетесь на встроенную функцию браузера (воображаемое слово для её запуска или выполнения), не может быть написана на JavaScript — многие из этих функций вызывают части фонового кода браузера, который написан в основном на системных языках низкого уровня, таких как C ++, а не на веб-языках, таких как JavaScript.</p> + +<p>Имейте в виду, что некоторые встроенные функции браузера не являются частью основного языка JavaScript — некоторые из них являются частью API браузера, которые основываются на языке по умолчанию, чтобы обеспечить еще большую функциональность (подробнее см. <a href="/ru/docs/Learn/JavaScript/Первые_шаги/What_is_JavaScript#Так_что_же_он_действительно_может_делать">один из предыдущих разделов этого курса</a>). Более подробно рассмотрим использование API браузера в более позднем модуле курса.</p> + +<h2 id="Функции_или_методы">Функции или методы</h2> + +<p>Одну вещь, которую нам нужно прояснить, прежде чем двигаться дальше - технически, встроенные функции браузера не являются функциями — это <strong>методы</strong>. Это звучит немного страшно и запутанно, но не волнуйтесь — функции и методы слова во многом взаимозаменяемы, по крайней мере для наших целей, на данном этапе вашего обучения.</p> + +<p>Разница между методом и функцией лишь в том, что методы - это функции, определенные внутри объектов. Встроенные функции (методы) браузера и переменные (так называемые <strong>свойства</strong>) хранятся внутри структурированных объектов, чтобы сделать код более эффективным и более простым в использовании.</p> + +<p>Вам пока не нужно изучать внутреннюю работу структурированных объектов JavaScript - вы можете подождать, пока наш более поздний модуль не научит вас внутренним работам объектов и тому, как создавать свои собственные. На данный момент мы просто хотим устранить любую возможную путаницу метода, в сравнении с функциями - вы, вероятно, встретите оба термина, когда будете смотреть на доступные связанные ресурсы через Интернет.</p> + +<h2 id="Пользовательские_функции">Пользовательские функции</h2> + +<p>В этом курсе так же использовались <strong>пользовательские функции</strong> — это функции, которые вы определяете в своем коде, а не внутри браузера. Каждый раз, когда вы видели произвольное слово (имя функции) с круглыми скобками прямо после него, вы использовали пользовательскую функцию. В нашем примере <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> (подробнее см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">исходный код</a>) из нашей <a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">статьи о циклах</a> мы включили пользовательскую функцию <code>draw()</code>, которая выглядит так:</p> + +<pre class="brush: js notranslate">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(); + } +}</pre> + +<p>Эта функция рисует 100 случайных кругов внутри элемента {{htmlelement("canvas")}}. Каждый раз, когда мы хотим это сделать, мы можем вызвать эту функцию следующим образом</p> + +<pre class="brush: js notranslate">draw();</pre> + +<p>вместо того, чтобы каждый раз, когда мы хотим повторить этот код, не писать его заново. И функции могут содержать любой код, который вам нравится - вы можете даже вызывать другие функции внутри своих функций. Вышеупомянутая функция, например, вызывает функцию <code>random()</code> три раза, которая выглядит следующим образом:</p> + +<pre class="brush: js notranslate">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p>Нам понадобилась эта функция, потому что встроенная в браузер функция <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> генерирует случайное дробное число от 0 до 1. Но мы хотим случайное целое число от 0 до указанного числа.</p> + +<h2 id="Вызов_функций">Вызов функций</h2> + +<p>Скорее всего, вы уже поняли это, но на всякий случай ... чтобы использовать функцию после того, как она была определена, вам нужно запустить или вызвать ее. Это делается путем включения имени функции в код где-нибудь, за которым следуют скобки.</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('привет'); +} + +myFunction() +// Единовременный вызов функции</pre> + +<h2 id="Безымянные_функции">Безымянные функции</h2> + +<p>Вы можете видеть функции, определенные и вызываемые несколькими разными способами. До этого мы создавали функции таким способом:</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('привет'); +}</pre> + +<p>Но вы также можете создавать функции без имени:</p> + +<pre class="brush: js notranslate">function() { + alert('привет'); +}</pre> + +<p>Такая функция называется <strong>безымянная функция</strong> (или анонимная) — она не имеет имени! Она сама по себе ничего не делает. Обычно такие функции используются вместе с обработчиком событий, например, следующее будет вызывать код внутри функции каждый раз, по нажатию соответствующей кнопки:</p> + +<pre class="brush: js notranslate">var myButton = document.querySelector('button'); + +myButton.onclick = function() { + alert('привет'); +}</pre> + +<p>В приведенном примере требуется, чтобы на странице был элемент {{htmlelement ("button")}} (кнопка), которую нужно нажать. Вы уже видели такую структуру несколько раз на протяжении всего курса, подробнее о ней вы узнаете из следующей статьи.</p> + +<p>Вы также можете присвоить к переменной анонимную функцию, например:</p> + +<pre class="brush: js notranslate">var myGreeting = function() { + alert('привет'); +}</pre> + +<p>Теперь эту функцию можно вызвать, используя:</p> + +<pre class="brush: js notranslate">myGreeting();</pre> + +<p>Фактически такой способ присваивает переменной имя; вы также можете присвоить функцию значением нескольких переменных, например:</p> + +<pre class="brush: js notranslate">var anotherGreeting = function() { + alert('привет'); +}</pre> + +<p>Теперь функцию можно вызвать, используя любую из переменных</p> + +<pre class="brush: js notranslate">myGreeting(); +anotherGreeting();</pre> + +<p>Но это может ввести в заблуждение, так что не стоит так делать! При создании функций лучше всего придерживаться следующего вида:</p> + +<pre class="brush: js notranslate">function myGreeting() { + alert('привет'); +}</pre> + +<p>Чаще всего вы будете использовать анонимные функции, чтобы просто запускать код при срабатывания события - например, нажатие кнопки - с помощью обработчика событий. Опять же, это выглядит примерно так:</p> + +<pre class="brush: js notranslate">myButton.onclick = function() { + alert('привет'); + // При желании, внутри этой функции + // можно написать много кода. +}</pre> + +<h2 id="Параметры_функции">Параметры функции</h2> + +<p>Некоторые функции при их вызове требуют указание параметров — это значения, которые должны быть вставлены в круглые скобки функции, необходимые для корректной работы функции.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Параметры иногда называются аргументами, свойствами или атрибутами.</p> +</div> + +<p>Например встроенная в браузер функция <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> не требует параметров. При вызове, она всегда возвращает случайное число от 0 до 1:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random();</pre> + +<p>Браузерная встроенная функция, работающая со строкой, <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> ожидает два параметра — это подстрока для поиска в основной строке и строка, на которую происходит замена в основной строке:</p> + +<pre class="brush: js notranslate">var myText = 'Я строка'; +var newString = myText.replace('строка', 'сосиска');</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Если необходимо указать несколько параметров, их разделяют запятыми.</p> +</div> + +<p>Следует также отметить, что иногда параметры являются необязательными - вам не нужно их указывать. Если вы этого не сделаете, функция, как правило, примет какое-то поведение по умолчанию. В качестве примера параметр функции массива <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/join">join()</a> необязателен:</p> + +<pre class="brush: js notranslate">var myArray = ['Я', 'люблю', 'шоколадных', 'лягушек']; +var madeAString = myArray.join(' '); +// Вернет 'Я люблю шоколадных лягушек' +var madeAString = myArray.join(); +// Вернет 'Я,люблю,шоколадных,лягушек'</pre> + +<p>Если не указан параметр для символа соединения / разграничения, по умолчанию используется запятая.</p> + +<h2 id="Область_видимости_функции_и_конфликты">Область видимости функции и конфликты</h2> + +<p>Давайте немного поговорим о {{glossary("scope")}} - очень важная концепция при работе с функциями. Когда вы создаете функцию, переменные и другие вещи, определенные внутри функции, находятся внутри их отдельной <strong>области (scope)</strong>, что означает, что они заперты в своих отдельных отсеках, недоступных из других функций или из кода вне функций.</p> + +<p>Верхний уровень за пределами всех ваших функций называется <strong>глобальной областью (global scope)</strong>. Значения, определенные в глобальном масштабе, доступны извне в коде.</p> + +<p>JavaScript настроен таким образом по разным причинам - но главным образом из-за безопасности и организации. Иногда вы не хотите, чтобы переменные были доступны извне в коде - внешние скрипты, которые вы вызывали из других источников, могут начать работать с вашим кодом и вызывать проблемы, потому что они используют одни и те же имена переменных, как и другие части кода , вызывая конфликты. Это может быть сделано злонамеренно или просто случайно.</p> + +<p>Например, скажем, у вас есть файл HTML, который вызывается в двух внешних файлах JavaScript, и оба они имеют переменную и определенную функцию, которые используют одно и то же имя:</p> + +<pre class="brush: html notranslate"><!-- Excerpt from my HTML --> +<script src="first.js"></script> +<script src="second.js"></script> +<script> + greeting(); +</script></pre> + +<pre class="brush: js notranslate">// first.js +var name = 'Chris'; +function greeting() { + alert('Hello ' + name + ': welcome to our company.'); +}</pre> + +<pre class="brush: js notranslate">// second.js +var name = 'Zaptec'; +function greeting() { + alert('Our company is called ' + name + '.'); +}</pre> + +<p>Обе функции, которые вы хотите вызвать, называются <code>greeting()</code>, но вы можете получить доступ только к функции <code>greeting()</code> файла <code>first.js</code> (функция файла <code>second.js</code> игнорируется). Кроме того, попытка объявить переменную <code>name</code> второй раз через <code>let</code> в файле <code>second.js</code> приведет к ошибке.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Этот пример можно увидеть в режиме <a href="https://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">Live на GitHub</a> (см. также <a href="/ru/docs/https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">исходный код</a>).</p> +</div> + +<p>Хранение частей вашего кода, заблокированных функциями, позволяет избежать таких проблем и считается наилучшей практикой.</p> + +<p>Это немного похоже на зоопарк. Львы, зебры, тигры и пингвины находятся в своих собственных ограждениях и имеют доступ только к вещам внутри их вольеров - таким же образом, как и в области функций. Если бы они смогли попасть в другие вольеры, возникли проблемы. В лучшем случае разные животные будут чувствовать себя неудобно в незнакомых местах обитания - лев или тигр будут чувствовать себя ужасно внутри водянистой, ледяной области пингвинов. В худшем случае львы и тигры могут попытаться съесть пингвинов!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p> + +<p>Хранитель зоопарка подобен глобальной переменной - он или она имеет ключи для доступа к каждому вольеру, для пополнения запасов пищи, ухода за больными животными и т. д.</p> + +<h3 id="Активное_обучение_игра_с_scope">Активное обучение: игра с scope</h3> + +<p>Давайте посмотрим на реальный пример, демонстрирующий обзор.</p> + +<ol> + <li>Сначала создайте локальную копию нашего примера <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html">function-scope.html</a>. Это содержит две функции, называемые <code>a()</code> и <code>b()</code>, и три переменные - <code>x</code>, <code>y</code> и <code>z</code> - две из которых определены внутри функций и одна в глобальной области. Он также содержит третью функцию, называемую <code>output()</code>, которая принимает один параметр и выводит его в абзаце на странице.</li> + <li>Откройте пример в браузере и в текстовом редакторе.</li> + <li>Откройте консоль JavaScript в инструментах разработчика вашего браузера. В консоли JavaScript введите следующую команду: + <pre class="brush: js notranslate">output(x);</pre> + Вы должны увидеть значение переменной <code>x</code> вывод на экране.</li> + <li>Теперь попробуйте ввести следующее в консоли + <pre class="brush: js notranslate">output(y); +output(z);</pre> + Оба из них должны возвращать ошибку в строке "<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: y is not defined</a>". Почему это? Из-за функции scope - <code>y</code> и <code>z</code> блокируются внутри функций <code>a() </code>и <code>b()</code>, поэтому <code>output()</code> не может получить к ним доступ при вызове из глобальной области.</li> + <li>Однако как насчет того, когда он вызван изнутри другой функции? Попробуйте отредактировать функции <code>a()</code> и <code>b()</code>, чтобы они выглядели следующим образом: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(y); +} + +function b() { + var z = 3; + output(z); +}</pre> + Сохраните код и перезагрузите его в своем браузере, затем попробуйте вызвать функции <code>a()</code> и <code>b()</code> из консоли JavaScript: + + <pre class="brush: js notranslate">a(); +b();</pre> + Вы должны увидеть значения y и z, выводимые на странице. Это отлично работает, так как функция <code>output() </code>вызывается внутри других функций - в той же области, где переменные, которые она печатает, определяются в каждом случае. <code>output()</code> доступен из любого места, поскольку он определен в глобальной области.</li> + <li>Теперь попробуйте обновить свой код следующим образом: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(x); +} + +function b() { + var z = 3; + output(x); +}</pre> + Сохраните и перезагрузите снова и повторите попытку в консоли JavaScript:</li> + <li> + <pre class="brush: js notranslate"><code>a(); +b();</code></pre> + + <p>Оба вызова <code>a()</code> и <code>b()</code> должны выводить значение x - 1. Они работают нормально, потому что, хотя вызовы <code>output()</code> не находятся в той же области, где определено <code>x</code>, <code>x</code> - глобальная переменная, поэтому она доступна внутри всего кода, везде</p> + </li> + <li>Наконец, попробуйте обновить свой код следующим образом: + <pre class="brush: js notranslate"><code>function a() { + var y = 2; + output(z); +} + +function b() { + var z = 3; + output(y); +}</code></pre> + Сохраните и перезагрузите снова и повторите попытку в консоли JavaScript:</li> + <li> + <pre class="brush: js notranslate"><code>a(); +b();</code></pre> + </li> +</ol> + +<p>На этот раз вызовы <code>a()</code> и <code>b()</code> возвратят эту раздражающую ошибку "<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" - это потому, что вызовы <code>output()</code> и переменные, которые они пытаются распечатать, не определены внутри одних и тех же областей функций - переменные эффективно невидимы для этих вызовов функций.</p> + +<div class="note"> +<p><strong>Примечание</strong>: Те же правила определения не применяются к циклу (например, <code>for() { ... }</code>) и условным блокам (например, <code>if() { ... }</code>) - они выглядят очень похожими, но это не одно и то же! Старайтесь не путать их.</p> +</div> + +<div class="note"> +<p><strong>Примечание:</strong> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: "x" is not defined</a>. Ошибка - это одна из наиболее распространенных проблем, с которой вы столкнетесь. Если вы получите эту ошибку, и вы уверены, что определили эту переменную, проверьте, в какой области она находится.</p> +</div> + +<ul> +</ul> + +<h3 id="Функции_внутри_функций">Функции внутри функций</h3> + +<p>Имейте в виду, что вы можете вызывать функцию из любого места, даже если она внутри другой функции. Это часто используется как способ поддержания чистоты кода. Если у вас есть большая сложная функция, ее легче понять, если разбить ее на несколько подфункций:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue; + + subFunction1(); + subFunction2(); + subFunction3(); +} + +function subFunction1() { + console.log(myValue); +} + +function subFunction2() { + console.log(myValue); +} + +function subFunction3() { + console.log(myValue); +} +</pre> + +<p>Просто убедитесь, что значения, используемые внутри функции, находятся в области видимости. В приведенном выше примере выдается ошибка <code>ReferenceError: MyValue is not defined</code>, поскольку хотя переменная <code>myValue</code> определена в той же области, что и вызовы функций, она не определена в определениях функций - фактический код, который запускается при вызове функций. Чтобы это работало, вам нужно передать значение в функцию в качестве параметра, например так:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue = 1; + + subFunction1(myValue); + subFunction2(myValue); + subFunction3(myValue); +} + +function subFunction1(value) { + console.log(value); +} + +function subFunction2(value) { + console.log(value); +} + +function subFunction3(value) { + console.log(value); +}</pre> + +<h2 id="Заключение">Заключение</h2> + +<p>В этой статье были рассмотрены основные понятия, лежащие в основе функций, позволяющие освоить следующий материал, в котором мы получим практические навыки, и научимся создавать собственные функции.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="/ru/docs/Web/JavaScript/Guide/Functions">Детальное руководство по функциям</a> — описание некоторых дополнительных функций, не описанных в этой статье.</li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Functions">Описание функций</a></li> + <li><a href="/ru/docs/Web/JavaScript/Reference/Functions/Default_parameters">Параметры по умолчанию</a>, <a href="/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Стрелочные функции</a> — продвинутая документация</li> +</ul> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p> diff --git a/files/ru/learn/javascript/building_blocks/image_gallery/index.html b/files/ru/learn/javascript/building_blocks/image_gallery/index.html new file mode 100644 index 0000000000..a0e1e48cd5 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/image_gallery/index.html @@ -0,0 +1,146 @@ +--- +title: Фотогалерея +slug: Learn/JavaScript/Building_blocks/Image_gallery +tags: + - Обработчик событий + - Оценка + - начальный уровень + - события + - циклы +translation_of: Learn/JavaScript/Building_blocks/Image_gallery +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Теперь, после изучения основ JavaScript, мы проверим ваши знания циклов, функций, условных операторов и событий предложив вам написать популярный элемент который вы увидите на многих сайтах - галерея на JavaScript.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые знания:</th> + <td> + <p>Перед выполнением этого задания вы должны проработать все статьи в этом модуле.</p> + </td> + </tr> + <tr> + <th scope="row">Цель:</th> + <td>Проверить понимание циклов, функций, условных операторов и событий в JavaScript.</td> + </tr> + </tbody> +</table> + +<h2 id="Отправная_точка">Отправная точка</h2> + +<p>Для начала скачайте <a href="https://github.com/ConstantineZz/learning-area/raw/master/javascript/building-blocks/gallery/gallery-start-rv.zip">ZIP файл</a> для примера и распакуйте его содержимое у себя на компьютере.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Вы также можете использовать такие сайты как <a class="external external-icon" href="http://jsbin.com/">JSBin</a> или <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> для выполнения задания. Вы можте скопировать HTML, CSS и JavaScript в один из этих редакторов. Если онлайн редактор, который вы выбрали, не имеет отдельных панелей для JavaScript/CSS, вы можете выставить код в теги <code><script></code>/<code><style></code> расположенные на самой HTML странице.</p> +</div> + +<h2 id="Обзор_проекта">Обзор проекта</h2> + +<p>В примере вы увидите несколько файлов HTML, CSS и изображений и несколько строк JavaScript кода. Вам нужно написать недостающий JavaScript код для того чтобы галерея заработала. Каркас HTML страницы выглядит так:</p> + +<pre class="brush: html"><h1>Пример фотогалереи</h1> + +<div class="full-img"> + <img class="displayed-img" src="images/pic1.jpg"> + <div class="overlay"></div> + <button class="dark">Темнее</button> +</div> + +<div class="thumb-bar"> + +</div></pre> + +<p>Результат выглядит следующим образом:</p> + +<p><img alt="" src="https://github.com/ConstantineZz/javaScript/blob/master/gallery.png?raw=true" style="height: 639px; width: 827px;"></p> + +<ul> +</ul> + +<p>Наиболее интересные части CSS файла из примера:</p> + +<ul> + <li>Абсолютно позиционированы три элемента внутри <code><div class="full-img"></code>: <code><img></code>, в котором отображается полноразмерное изображение, пустой <code><div class="overlay"></code>, размер которого имеет тот же размер, что и <code><img></code> помещается прямо над предыдущим div-ом (это используется для нанесения эффекта затемнения на изображение через полупрозрачный цвет фона) и <code><button></code>, который используется для управления эффектом затемнения.</li> + <li>Задана ширина любых изображений внутри <code><div class="thumb-bar"></code> (так называемые «уменьшенные изображения») до 20% и размещены слева так, чтобы они следовали друг за другом на линии.</li> +</ul> + +<p>Ваш JavaScript должен:</p> + +<ul> + <li>Переберите все изображения, и для каждого вставьте элемент <code><img></code> внутри <code>thumb-bar <div></code>, который будет вставлять это изображение на страницу.</li> + <li>Прикрепите обработчик <code>onclick</code> к каждому <code><img></code> внутри <code>thumb-bar <div></code>, чтобы при нажатии на них соответствующее изображение отображалось в элементе <code>display-img <img></code>.</li> + <li>Прикрепите обработчик <code>onclick</code> к кнопке <code><button></code>, чтобы при нажатии на нее к полноразмерному изображению был применен эффект затемнения. При повторном нажатии эффект затемнения снова удаляется.</li> +</ul> + +<p>Чтобы лучше понять идею, посмотрите на <a href="https://mdn.github.io/learning-area/javascript/building-blocks/gallery/">готовый пример</a> (не заглядывая в исходный код!).</p> + +<h2 id="Этапы_выполнения">Этапы выполнения</h2> + +<p>В следующих разделах описывается, что вам нужно делать.</p> + +<h3 id="Зацикливание_изображений">Зацикливание изображений</h3> + +<p>В файле main.js уже предоставлены строки, в которых хранится ссылка на <code>thumb-bar <div></code> внутри переменной с именем <code>thumbBar</code>, создают новый элемент <code><img></code>, устанавливают его атрибут <code>src</code> на значение placeholder <code>xxx</code> и добавляют этот новый <code><img></code> элемент внутри <code>thumbBar</code>.</p> + +<p>Нужно сделать:</p> + +<ol> + <li>Поместите раздел кода под комментарием <code>/* Looping through images */</code> внутри цикла, который перебирает все 5 изображений - вам просто нужно перебрать пять чисел, каждое из которых представляет каждое изображение.</li> + <li>В каждой итерации цикла замените значение-заполнитель <code>xxx</code> строкой, которая будет равна пути к изображению в каждом случае. Мы устанавливаем значение атрибута <code>src</code> для этого значения в каждом случае. Имейте в виду, что в каждом случае изображение находится внутри каталога изображений, а его имя - <code>pic1.jpg</code>, <code>pic2.jpg</code> и т.д.</li> +</ol> + +<h3 id="Добавление_обработчика_onclick_к_каждому_уменьшенному_изображению">Добавление обработчика onclick к каждому уменьшенному изображению</h3> + +<p>В каждой итерации цикла вам нужно добавить обработчик <code>onclick</code> к текущему <code>newImage</code>:</p> + +<ol> + <li>Найдите значение атрибута <code>src</code> текущего изображения. Это можно сделать, запустив функцию <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute">getAttribute()</a></code> в <code><img></code> в каждом случае и передав ей параметр <code>«src»</code> в каждом случае. Но как получить изображение? Использование <code>newImage</code> не будет работать, так как цикл завершается до применения обработчиков событий; это приведет к тому, что значение <code>src</code> последнего <code><img></code> будет возвращено в каждом случае. Чтобы решить это, имейте в виду, что в случае каждого обработчика события <code><img></code> является целью обработчика. Как получить информацию от объекта события?</li> + <li>Запустите функцию, передав ей возвращаемое значение <code>src</code> в качестве параметра. Вы можете вызвать эту функцию, как хотите.</li> + <li>Эта функция обработчика событий должна установить значение атрибута <code>src</code> <code>displayed-img <img></code> равным значению <code>src</code>, переданному в качестве параметра. Мы уже предоставили вам строку, в которой хранится ссылка на соответствующий <code><img></code> в переменной с именем <code>displayedImg</code>. Обратите внимание, что здесь нам нужна определенная именованная функция.</li> +</ol> + +<h3 id="Написание_обработчика_который_запускает_кнопку_затемнения_подсветки">Написание обработчика, который запускает кнопку затемнения / подсветки</h3> + +<p>Мы уже предоставили строку, в которой хранится ссылка на <code><button></code> в переменной <code>btn</code>. Вам нужно добавить обработчик <code>onclick</code>, который:</p> + +<ol> + <li>Проверяет текущее имя класса, установленное на кнопке <code><button></code> — для этого снова можно использовать <code>getAttribute()</code>.</li> + <li>Если имя класса <code>"dark"</code>, изменяет класс <code><button></code> на <code>"light"</code> (с помощью <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute">setAttribute()</a></code>), его текстовое содержимое на "Светлее" и {{cssxref("background-color")}} наложения <code><div></code> на <code>"rgba (0,0,0,0.5)"</code>.</li> + <li>Если имя класса не «темное», изменяет класс <code><button></code> на <code>"dark"</code>, его текстовое содержимое обратно на "Темнее" и {{cssxref("background-color")}} наложения <code><div></code> на <code>"rgba(0,0,0,0)"</code>.</li> +</ol> + +<p>Следующие строки служат основой для достижения изменений, указанных в пунктах 2 и 3 выше.</p> + +<pre class="brush: js">btn.setAttribute('class', xxx); +btn.textContent = xxx; +overlay.style.backgroundColor = xxx;</pre> + +<h2 id="Советы_и_подсказки">Советы и подсказки</h2> + +<ul> + <li>Вам не нужно каким-либо образом редактировать HTML или CSS.</li> +</ul> + +<h2 id="Оценка">Оценка</h2> + +<p>Если вы проводите эту оценку в рамках организованного курса, вы должны уметь отдать свою работу своему учителю/наставнику для маркировки. Если вы самообучаетесь, то вы можете получить руководство по маркировке довольно легко, задав тему <a href="https://discourse.mozilla.org/t/image-gallery-assessment/24687">обсуждения об этом упражнении</a> или в IRC-канале <a href="irc://irc.mozilla.org/mdn">#mdn</a> в <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Сначала попробуйте упражнение - ничего не выиграть от обмана!</p> + +<p>{{PreviousMenu("Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<p> </p> + +<h2 id="В_этом_модуле">В этом модуле</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — Переиспользуемые блоки кода</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою собственную функцию</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемое значение функции</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/%D0%A1%D0%BE%D0%B1%D1%8B%D1%82%D0%B8%D1%8F">Введение в события</a></li> + <li><a href="https://developer.mozilla.org/ru/docs/Learn/JavaScript/Building_blocks/Image_gallery">Создание галереи</a></li> +</ul> diff --git a/files/ru/learn/javascript/building_blocks/index.html b/files/ru/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..16b54aff16 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/index.html @@ -0,0 +1,61 @@ +--- +title: Структурные элементы JavaScript +slug: Learn/JavaScript/Building_blocks +tags: + - JavaScript + - Введение + - Гид + - Знакомство + - Модуль + - Написание кода + - НаписаниеКода + - Начинающий + - Новичок + - Оценивание + - Раздел + - Руководство + - Статья + - Условия + - Функции + - лендинг + - события + - циклы +translation_of: Learn/JavaScript/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">В данном разделе мы продолжим знакомство с ключевыми основами JavaScript, обратим внимание на часто используемые приёмы программирования, такие как условные выражения, циклы, функции и события. Все они уже встречались Вам ранее в данном курсе, но только поверхностно, далее они будут рассмотрены подробнее.</p> + +<h2 id="Предварительное_условие">Предварительное условие</h2> + +<p>До начала изучения следующего раздела Вам нужно тщательно ознакомиться с основами <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML</a> и <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS</a>, так же обязательно прочтите курс "<a href="/ru/docs/Learn/JavaScript/%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B5_%D1%88%D0%B0%D0%B3%D0%B8">Первые шаги в JavaScript</a>".</p> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>Примечание</strong></span>: если устройство на котором Вы изучаете данный курс не позволяет создавать/сохранять файлы, в большинстве случаев примеры кода могут быть запущены в таких онлайн приложениях как <a href="http://jsbin.com/">JSBin</a> или <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Руководства">Руководства</h2> + +<dl> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/conditionals">Принятие решений в Вашем коде — условные конструкции</a></dt> + <dd>В любом языке программирования необходимо принимать решения и совершать действия в зависимости от полученных в процессе исполнения программы или введённых пользователем данных. Например, игра должна завершиться, когда число жизней персонажа игрока достигает нуля. В приложении для прогноза погоды отображается картинка с восходящим солнцем, если смотреть утром, со звёздами и луной — ночью. В данной статье исследуется работа условных конструкций в JavaScript.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Looping_code">Зацикливание кода</a></dt> + <dd>Иногда требуется, чтобы действие исполнялось несколько раз подряд. Например, при просмотре списка имён. В программировании для данной цели успешно применяются циклы. Здесь мы познакомимся с использованием циклов в JavaScript.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Functions">Функции — блоки кода используемые многократно</a></dt> + <dd>Другая необходимая концепция в программировании это <strong>функции</strong>. <strong>Функции</strong> позволяют сохранить часть кода для решения определённой задачи в определённом блоке, и затем вызывать этот код, тогда, когда это тебе необходимо при помощи короткой команды — это намного лучше, чем писать один и тот же код несколько раз. В статье будут рассмотрена фундаментальная концепция функции: основной синтаксис, как вызывать и как определять функции, области видимости и параметры.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создай свою функцию</a></dt> + <dd>В отличие от большинства предыдущих статей, рассматривающих только теорию, эта статья даёт практический опыт. Здесь вы получите практику создания собственных функций. На ряду с возможностями, мы также объясним дополнительные полезные подробности, связанные с функциями.</dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/Return_values">Функции возвращают значения</a></dt> + <dd>Есть одно из существенных понятий для нас, представленное в этом курсе, которое достойно пристального внимания — возврат значений функции. Некоторые функции не возвращают значений после завершения, но другие делают это. Главное понять, что это за значения, как использовать их в Вашем коде, и как заставить Вашу собственную функцию возвратить необходимые значения. </dd> + <dt><a href="/ru/docs/Learn/JavaScript/Building_blocks/События">Введение в события</a></dt> + <dd>События — это действия или явления, которые происходят в системе во время программирования, о которых система сообщает, и, при желании, на которые можно ответить. Например, когда пользователь кликает на кнопку на странице, возможно Вы захотите вывести на экран блок с информацией, как ответ на это событие. В последней статье мы обсудим важные концепции, связанные с событиями, и увидим, как они работают в браузерах.</dd> +</dl> + +<h2 id="Проверка_знаний">Проверка знаний</h2> + +<p>Следующая оценка проверит Ваше понимание основ JavaScript, описанных в данном руководстве.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Фотогалерея</a></dt> + <dd>Теперь, когда мы рассмотрели основные блоки JavaScript, мы проверим твои знания о циклах, функциях, регулярных выражениях и событиях, создав довольно общий элемент, который вы увидите на многих сайтах - галерея изображений, работающей с помощью JavaScript.</dd> +</dl> 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> diff --git a/files/ru/learn/javascript/building_blocks/return_values/index.html b/files/ru/learn/javascript/building_blocks/return_values/index.html new file mode 100644 index 0000000000..016321c969 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/return_values/index.html @@ -0,0 +1,172 @@ +--- +title: Возвращаемое значение функции +slug: Learn/JavaScript/Building_blocks/Return_values +translation_of: Learn/JavaScript/Building_blocks/Return_values +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/События", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">Для нас в этом курсе имеется еще один важный момент. Посмотрим внимательнее на возвращаемое значение функций. Некоторые функции не возвращают существенное значение после завершения, но некоторые возвращают, и важно понимать что это за значение и как использовать его в своем коде и как сделать так чтобы ваши собственные функции возвращали полезные значения. Мы объясним всё это ниже. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Необходимые навыки:</th> + <td> + <p>Базовая компьютерная грамотность, знание основ HTML и CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a>.</p> + </td> + </tr> + <tr> + <th scope="row">Цели:</th> + <td>Понять что такое возвращаямое значение функции и как его использовать.</td> + </tr> + </tbody> +</table> + +<h2 id="Что_из_себя_представляют_возвращаемые_значения">Что из себя представляют возвращаемые значения?</h2> + +<p><strong>Возвращаемые значения </strong>- это на самом деле просто значения, которые функция возвращает после своего завершения. Вы уже неоднократно встречали возвращаемые значения, хотя, возможно, и не осознавали этого. Напишем небольшой код: </p> + +<pre class="brush: js">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// функция replace() принимает строку, +// заменяет одну подстроку другой и возвращает +// новую строку со сделанными заменами</pre> + +<p>Мы уже видели этот блок кода в нашей первой статье про функции. Мы вызываем функцию <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a> на строке <code>myText</code> и передаем ей 2 параметра — заменяемую подстроку и подстроку, которой будем заменять. Когда функция завершит выполнение, она вернет значение, которым является новая строка со сделанными в ней заменами. В коде выше мы сохраняем это возвращаемое значение как значение переменной <code>newString</code>.</p> + +<p>Если Вы посмотрите на функцию replace() на MDN reference page, вы увидите секцию под названием <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Return_value">Return value</a>. Очень важно знать и понимать какие значения возвращаются функциями, так что мы пытаемся включать эту информацию везде, где это возможно.</p> + +<p>Некоторые функции не возвращают значения( на наших reference pages, возвращаемое значение обозначено как <code>void</code> или <code>undefined</code> в таких случаях). Например, в функции <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html#L50">displayMessage()</a> которую мы сделали в прошлой статье, в результате выполнения функции не возвращается никакого значения. Функция всего лишь отображает что-то где-то на экране.</p> + +<p>В основном, возвращаемое значение используется там, где функция является чем-то вроде вспомогательного звена при вычислениях. Вы хотите получить результат, который включает в себя некоторые значения. Эти значения вычисляются функцией, которая возвращает результат так, что он может быть использован в следующих стадиях вычисления.</p> + +<h3 id="Использование_возвращаемых_значений_в_ваших_собственных_функциях">Использование возвращаемых значений в ваших собственных функциях</h3> + +<p>Чтобы вернуть значение своей функции, вы должны использовать ключевое слово <a href="/en-US/docs/Web/JavaScript/Reference/Statements/return">return</a>. Мы видели это в действии недавно - в нашем примере <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a>. Наша функция<code>draw()</code>отрисовывает где-то на экране 100 случайных кружков. </p> + +<p>{{htmlelement("canvas")}}:</p> + +<pre class="brush: js">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(); + } +}</pre> + +<p>Внутри каждой итерации есть 3 вызова функции <code>random()</code>. Это сделано чтобы сгенерировать случайное значение для текущей координаты x, y и для радиуса. Функция <code>random()</code> принимает 1 параметр (целое число) и возвращает случайное число в диапазоне от 0 до этого числа. Выглядит это вот так: </p> + +<pre class="brush: js">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p>Тоже самое может быть написано вот так:</p> + +<pre class="brush: js">function random(number) { + var result = Math.floor(Math.random()*number); + return result; +}</pre> + +<p>Но первую версию написать быстрее и она более компактна.</p> + +<p>Мы возвращаем результат вычисления <code>Math.floor(Math.random()*number)</code> каждый раз когда функция вызывается. Это возвращаемое значение появляется в момент вызова функции и код продолжается. Так, например, если мы выполним следующую строчку:</p> + +<pre class="brush: js">ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);</pre> + +<p>и 3 вызова <code>random()</code> вернут значения 500, 200 и 35, соответственно, строчка будет выполнена как если бы она была такой:</p> + +<pre class="brush: js">ctx.arc(500, 200, 35, 0, 2 * Math.PI); +</pre> + +<p>Сначала выполняются вызовы функции <code>random()</code>, на место которых подставляются возвращаемые ей значения, а затем выполнятся сама строка.</p> + +<h2 id="Активное_обучение_наша_собственная_возвращающая_значение_функция">Активное обучение: наша собственная, возвращающая значение функция</h2> + +<p>Теперь напишем нашу собственную возвращающую значение функцию.</p> + +<ol> + <li>Первым делом, сделайте локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library.html">function-library.html</a> из GitHub. Это простая HTML страничка, содержащая текстовое поле {{htmlelement("input")}} и параграф Также там есть элемент {{htmlelement("script")}} в котором мы храним в 2ух переменных ссылки на оба HTML элемента. Это маленькая страничка позволит Вам ввести число в text box и отобразит различные, относящиеся к нему числа в параграфе ниже.</li> + <li>Теперь добавим несколько полезных функций в элемент <code><script></code> . Ниже двух существующих строчек JavaScript, добавьте следующие описания функций: + <pre class="brush: js">function squared(num) { + return num * num; +} + +function cubed(num) { + return num * num * num; +} + +function factorial(num) { + var x = num; + while (x > 1) { + num *= x-1; + x--; + } + return num; +}</pre> + <code>Ф</code>ункции <code>squared()</code> и <code>cubed()</code> довольно очевидны— они возвразают квадрат или куб переданного как параметр числа. Функция <code>factorial()</code> возвращает <a href="https://en.wikipedia.org/wiki/Factorial">factorial</a> переданного числа.</li> + <li>Далее мы добавим способ выводить нашу информацию введенным в text input числе. Добавьте обработчик событий ниже существующих функций: + <pre class="brush: js">input.onchange = function() { + var num = input.value; + if (isNaN(num)) { + para.textContent = 'You need to enter a number!'; + } else { + para.textContent = num + ' squared is ' + squared(num) + '. ' + + num + ' cubed is ' + cubed(num) + '. ' + + num + ' factorial is ' + factorial(num) + '.'; + } +}</pre> + + <p>Здесь мы создаем обработчик событий <code>onchange</code> который срабатывает когда меняется когда новое значение вводится в text input и подтверждается (введите значение и, например, нажмите tab). Когда анонимная функция срабатывает, введенное в input значение сохраняется в переменной <code>num</code> .</p> + </li> + <li> + <p>Далее мы делаем условный тест — если введенное значение не является чилом, мы выводим в параграф сообщение об ошибке . Тест смотрит возвращает ли выражение <code>isNaN(num)</code> true. Мы используем функцию <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN">isNaN()</a> чтобы проверить что значение переменной num не число — если так то функция возвращает<code>true</code>, если нет- <code>false</code>.</p> + </li> + <li> + <p>Если тест возвращает <code>false</code>, значение переменной <code>num</code>число, и поэтому мы выводим сообщение внутри параграфа о значениях квадрата, куба и факториала числа. Предложение вызывает функции <code>squared()</code>, <code>cubed()<font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;"> и</span></font></code><code>factorial()</code> чтобы получить нужные значения. Сохраните Ваш код, загрузите его в браузере и посмотрите на то что получилось.</p> + </li> +</ol> + +<div class="note"> +<p><strong>Замечание</strong>: Если у вас проблемы с работой данного примера, не стесняйтесь сверить ваш код с работающей версией <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-library-finished.html">finished version on GitHub</a> (или <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-library-finished.html">смотрите живой пример</a>), или спросите нас.</p> +</div> + +<p>К этому моменту мы хотели бы чтобы вы написали парочку собственных функций и добавили их в библиотеку. Как на счет квадратного или кубического корня числа или длины окружности круга с длиной радиуса равной числу <code>num</code>?</p> + +<p>Это упражнение привнесло парочку важных понятий в изучении того, как использовать ключевое слово <code>return</code> . В дополнение:</p> + +<ul> + <li>Приведите другой пример написание обработчика ошибок. Это довольно хорошая идея проверять что важные параметры предоставлены в правильном типе и если они опциональны то предусматривать для них значения по умолчанию. В таком случая Ваша программа с меньшей вероятность подвержена ошибкам. </li> + <li>Поразмышляйте о идее создания библиотеки функций. Чем дальше Вы будите расти в профессиональном плане, тем больше будете сталкиваться с однотипными вещами. Это хорошая идея начать собирать свою собственную библиотеку функций, которые Вы часто используюте — в таком случае Вы сможете просто скопировать их в Ваш новый код или просто добавить их в любую HTML страничку, где это требуется.</li> +</ul> + +<h2 id="Заключение">Заключение</h2> + +<p>Функции очень полезны и не смотря на то, что об их синтаксисе и функциональности можно говорить долго, у нас есть довольно понятные статьи для дальнейшего обучения.</p> + +<p>Если в статье есть что-то что вы не поняли, не стесняйтесь перечитать статью еще раз или <a href="/en-US/Learn#Contact_us">свяжитесь с нами</a> для получения помощи.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions">Функции более подробно</a> — подробное руководство, охватывающее более продвинутую информацию, связанную с функциями.</li> + <li><a href="https://www.impressivewebs.com/callback-functions-javascript/">Функции обратного вызова в JavaScript</a> — распространенный паттерн JavaScript для передачи функции в другую функцию как аргумент, который затем вызывается внутри первой функици.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Build_your_own_function","Learn/JavaScript/Building_blocks/Events", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html b/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html new file mode 100644 index 0000000000..62e1951fdc --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/test_your_skills_colon__functions/index.html @@ -0,0 +1,99 @@ +--- +title: 'Проверь свои навыки: Функции' +slug: 'Learn/JavaScript/Building_blocks/Test_your_skills:_Functions' +tags: + - JavaScript + - Изучение + - Новичек + - Функции +translation_of: 'Learn/JavaScript/Building_blocks/Test_your_skills:_Functions' +--- +<div>{{learnsidebar}}</div> + +<p>Целью данного теста навыков является оценка понимания таких статей, как: <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Функций — многократное использование блоков кода</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Построение своих собственных функций</a> и <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Возвращаемые значения функции</a>.</p> + +<div class="blockIndicator note"> +<p>Примечание: Вы можете проверить решения в интерактивных редакторах ниже, однако может быть полезно загрузить код и использовать онлайн-инструменты, такие как <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a> для работы над задачами.<br> + <br> + Если у вас возникла проблема, то попросите нас о помощи - см. раздел {{anch("Анализ или дальнейшая помощь")}} внизу этой страницы.</p> +</div> + +<div class="blockIndicator note"> +<p>Примечание: В примерах ниже, если в вашем коде есть ошибка, она будет выведена на панель результатов этой страницы, чтобы помочь вам попытаться выяснить ответ (или в JavaScript консоли браузера, в случае загружаемой версии).</p> +</div> + +<h2 id="Управление_структурой_DOM_рекомендуется">Управление структурой DOM: рекомендуется</h2> + +<p>Некоторые из вопросов, приведенных ниже, требуют написания кода для управления структурой <a href="/en-US/docs/Glossary/DOM">DOM</a> для их решения - например, создание новых HTML-элементов, установка их текстового содержимого в соответствие с определенными значениями строк, и вложение их внутри существующих элементов на странице - и все это с помощью JavaScript.</p> + +<p>Мы еще не обучали этому прямо в курсе, но вы увидите некоторые примеры, которые используют данную структуру, и мы хотели бы, чтобы вы провели некоторые исследования в отношении того, какие DOM API вам нужны, чтобы успешно ответить на эти вопросы. Хорошим началом будет наше учебное пособие <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Управление документами</a>.</p> + +<h2 id="Функции_1">Функции 1</h2> + +<p>Для решения первой задачи вам нужно создать простую функцию — <code>chooseName()</code>, которая выполнит выборку случайного имени из данного массива (<code>names</code>) и выведет его в предоставленный параграф (<code>para</code>). А затем необходимо запустить эту функцию один раз.</p> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions1.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions1-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Функции_2">Функции 2</h2> + +<p>Для решения второй задачи, связанной с функциями, необходимо создать функцию, которая рисует прямоугольник на заданном элементе <code><canvas></code> (исходная переменная <code>canvas</code>, контекст доступен в <code>ctx</code>), основанном на пяти предоставленных входящих значениях:</p> + +<ul> + <li><code>x</code> — x координата прямоугольника.</li> + <li><code>y</code> — y координата прямоугольника.</li> + <li><code>width</code> — ширина прямоугольника.</li> + <li><code>height</code> — высота прямоугольника.</li> + <li><code>color</code> — цвет прямоугольника.</li> +</ul> + +<p>Перед рисованием вам нужно будет очистить содержимое элемента canvas , чтобы при обновлении кода в случае с рабочей версией, вы не получили много прямоугольников, находящихся друг на друге.</p> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions2.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions2-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Функции_3">Функции 3</h2> + +<p>В этой задаче вы возвращаетесь к проблеме, поставленной в Задаче 1, с целью ее улучшения. Мы хотим, чтобы вы сделали три улучшения:</p> + +<ol> + <li>Выполните рефакторинг (реорганизацию) кода, который отвечает за генерацию случайного числа в отдельную функцию <code>random()</code>, которая принимает в качестве параметров две общие границы, между которыми должно находиться случайное число и возвращает результат.</li> + <li>Обновите функцию <code>chooseName()</code> таким образом, чтобы она использовала функцию случайных чисел, принимала массив для выбора в качестве параметра (что делает его более гибким) и возвращала результат.</li> + <li>Вывести возвращаемый результат в параграф (<code>para</code>) с помощью свойства <code>textContent</code>. </li> +</ol> + +<p>Попробуйте обновить рабочий код ниже, чтобы воссоздать готовый пример:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/building-blocks/tasks/functions/functions3.html", '100%', 400)}}</p> + +<div class="blockIndicator note"> +<p><a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/tasks/functions/functions3-download.html">Загрузите файл с исходным кодом для этой задачи</a> для работы в собственном редакторе или в онлайн-редакторе.</p> +</div> + +<h2 id="Анализ_или_дальнейшая_помощь">Анализ или дальнейшая помощь</h2> + +<p>Вы можете попрактиковаться на этих примерах в интерактивных редакторах выше.</p> + +<p>Если же вы хотите, чтобы вашу работу проанализировали, или у вас проблема и вы хотите попросить о помощи:</p> + +<ol> + <li>Поместите свой код в онлайн-редактор <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a> или <a href="https://glitch.com/">Glitch</a> с возможностью совместного использования. Вы можете написать код самостоятельно или использовать файлы с исходным кодом, ссылки на которые приведены в вышеприведенных разделах.</li> + <li>Напишите сообщение с просьбой о проведении анализа и/или помощи в категории <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a>. Ваше сообщение должно включать в себя следующие пункты: + <ul> + <li>Описательный заголовок, например "Анализ для теста навыков: Функции 1".</li> + <li>Детали того, что вы уже пробовали, и что бы вы хотели, чтобы мы сделали, например, если вы застряли и нуждаетесь в помощи, или хотите получить анализ проблемы.</li> + <li>Ссылка на пример, который вы хотели бы рассмотреть или с которым вам нужна помощь, в онлайн-редакторе, доступном для совместного использования (как упоминалось в шаге 1 выше). Это хорошая практика - очень сложно помочь кому-то с проблемой, если вы не видите его код.</li> + <li>Ссылка на фактическую задачу или страницу рассмотрения проблемы, чтобы мы могли найти вопрос, по которому вам нужна помощь.</li> + </ul> + </li> +</ol> diff --git a/files/ru/learn/javascript/building_blocks/события/index.html b/files/ru/learn/javascript/building_blocks/события/index.html new file mode 100644 index 0000000000..db13cec676 --- /dev/null +++ b/files/ru/learn/javascript/building_blocks/события/index.html @@ -0,0 +1,606 @@ +--- +title: Введение в события +slug: Learn/JavaScript/Building_blocks/События +tags: + - Изучение + - Обработчик событий + - Руководство + - события +translation_of: Learn/JavaScript/Building_blocks/Events +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">События — это действия или случаи, возникающие в программируемой вами системе, о которых система сообщает вам для того, чтобы вы могли с ними взаимодействовать. Например, если пользователь нажимает кнопку на веб-странице, вы можете ответить на это действие, отобразив информационное окно. В этой статье мы обсудим некоторые важные концепции, связанные с событиями, и посмотрим, как они работают в браузерах. Эта статья не является исчерпывающим источником по этой теме — здесь только то, что вам нужно знать на этом этапе.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Предпосылки:</th> + <td>Базовая компьютерная грамотность, базовое понимание HTML и CSS, <a href="/ru/docs/Learn/JavaScript/Первые_шаги">Первые шаги в JavaScript</a>.</td> + </tr> + <tr> + <th scope="row">Задача:</th> + <td>Понять фундаментальную теорию событий, как они работают в браузерах и как события могут различаться в разных средах программирования.</td> + </tr> + </tbody> +</table> + +<h2 id="Серия_удачных_событий">Серия удачных событий</h2> + +<p>При возникновении <strong>события</strong> система генерирует сигнал, а также предоставляет механизм, с помощью которого можно автоматически предпринимать какие-либо действия (например, выполнить определенный код), когда происходит событие. Например, в аэропорту, когда взлетно-посадочная полоса свободна для взлета самолета, сигнал передается пилоту, и в результате они приступают к взлету.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/17376/MDN-mozilla-events-runway.png" style="height: 443px; width: 700px;"></p> + +<p>В Web события запускаются внутри окна браузера и, как правило, прикрепляются к конкретному элементу, который в нем находится. Это может быть один элемент, набор элементов, документ HTML, загруженный на текущей вкладке, или все окно браузера. Существует множество различных видов событий, которые могут произойти, например:</p> + +<ul> + <li>Пользователь кликает мышью или наводит курсор на определенный элемент.</li> + <li>Пользователь нажимает клавишу на клавиатуре.</li> + <li>Пользователь изменяет размер или закрывает окно браузера.</li> + <li>Завершение загрузки веб-страницы.</li> + <li>Отправка данных через формы.</li> + <li>Воспроизведение видео, пауза или завершение воспроизведения.</li> + <li>Произошла ошибка.</li> +</ul> + +<p>Подробнее о событиях можно посмотреть в <a href="/ru/docs/Web/Events">Справочнике по событиям</a>.</p> + +<p><span>Каждое доступное событие имеет </span><strong>обработчик событий<strong> </strong></strong>—<span> блок кода (обычно это функция JavaScript, вводимая вами в качестве разработчика), который будет запускаться при срабатывании события. Когда такой блок кода определен на запуск в ответ на возникновение события, мы говорим, что мы </span><strong>регистрируем обработчик событий</strong><span>. Обратите внимание, что обработчики событий иногда называют </span><strong>прослушивателями событий (event listeners).</strong><span> Они в значительной степени взаимозаменяемы для наших целей, хотя, строго говоря, они работают вместе. Прослушиватель отслеживает событие, а обработчик </span>— <span>это код, который запускается в ответ на событие.</span></p> + +<div class="note"> +<p><strong>Примечание:</strong> Важно отметить, что веб-события не являются частью основного языка JavaScript. Они определены как часть JavaScript-API, встроенных в браузер.</p> +</div> + +<h3 id="Простой_пример">Простой пример</h3> + +<p>Рассмотрим простой пример. Вы уже видели события и обработчики событий во многих примерах в этом курсе, но давайте повторим для закрепления информации. В этом примере у нас есть кнопка {{htmlelement ("button")}}, при нажатии которой цвет фона изменяется случайным образом:</p> + +<pre class="brush: html notranslate"><button>Change color</button></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">button { margin: 10px };</pre> +</div> + +<p>JavaScript выглядит так:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function random(number) { + return Math.floor(Math.random() * (number+1)); +} + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>В этом коде мы сохраняем ссылку на кнопку внутри переменной <code>btn</code> типа <code>const</code>, используя функцию {{domxref ("Document.querySelector()")}}. Мы также определяем функцию, которая возвращает случайное число. Третья часть кода — <a href="#Свойства_обработчика_событий">обработчик события</a>. Переменная <code>btn</code> указывает на элемент <code><button></code> — для этого типа объекта существуют возникающие при определенном взаимодействии с ним события, а значит, возможно использование обработчиков событий. Мы отслеживаем момент возникновения события при щелчке мышью, связывая свойство обработчика события <code>onclick</code> с анонимной функцией, генерирующей случайный цвет RGB и устанавливающей его в качестве цвета фона элемента <code><body></code>.</p> + +<p>Этот код теперь будет запускаться всякий раз, когда возникает событие при нажатии на элемент <code><button></code> — всякий раз, когда пользователь щелкает по нему.</p> + +<p>Пример вывода выглядит следующим образом:</p> + +<p>{{ EmbedLiveSample('Простой_пример', '100%', 200, "") }}</p> + +<h3 id="События_не_только_для_веб-страниц">События не только для веб-страниц</h3> + +<p>События, как понятие, относятся не только к JavaScript — большинство языков программирования имеют модель событий, способ работы которой часто отличается от модели в JavaScript. Фактически, даже модель событий в JavaScript для веб-страниц отличается от модели событий для просто JavaScript, поскольку используются они в разных средах.</p> + +<p>Например, <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs">Node.js</a> — очень популярная среда исполнения JavaScript, которая позволяет разработчикам использовать JavaScript для создания сетевых и серверных приложений. <a href="https://nodejs.org/docs/latest-v5.x/api/events.html">Модель событий Node.js</a> основана на том, что существуют прослушиватели, отслеживающие события, и эмиттеры (передатчики), которые периодически генерируют события. В общем-то, это похоже на модель событий в JavaScript для веб-страниц, но код совсем другой. В этой модели используется функция <code>on()</code> для регистрации прослушивателей событий, и функция <code>once()</code> для регистрации прослушивателя событий, который отключается после первого срабтывания. Хорошим примером использования являются протоколы событий <a href="https://nodejs.org/docs/latest-v8.x/api/http.html#http_event_connect">HTTP connect event docs</a>.</p> + +<p>Вы также можете использовать JavaScript для создания кросс-браузерных расширений — улучшения функциональности браузера с помощью технологии <a href="https://developer.mozilla.org/ru/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a>. В отличии от модели веб-событий здесь свойства прослушивателей событий пишутся в так называемом регистре <a href="https://ru.wikipedia.org/wiki/CamelCase">CamelCase</a> (например, <code>onMessage</code>, а не <code>onmessage</code>) и должны сочетаться с функцией <code>addListener</code>. См. <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/onMessage#Examples">runtime.onMessage page</a> для примера.</p> + +<p>На данном этапе обучения вам не нужно особо разбираться в различных средах программирования, однако важно понимать, что принцип работы <em>событий</em> в них отличается.</p> + +<h2 id="Способы_использования_веб-событий">Способы использования веб-событий</h2> + +<p>Существует множество различных способов добавления кода прослушивателя событий на веб-страницы так, чтобы он срабатывал при возникновении соответствующего события. В этом разделе мы рассмотрим различные механизмы и обсудим, какие из них следует использовать.</p> + +<h3 id="Свойства_обработчика_событий">Свойства обработчика событий</h3> + +<p>В этом курсе вы уже сталкивались со свойствами, связываемыми с алгоритмом работы обработчика событий. Вернемся к приведенному выше примеру:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +btn.onclick = function() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>В данной ситауции свойство <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick">onclick</a></code> — это свойство обработчика события. В принципе это обычное свойство кнопки как элемента (наравне с <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent">btn.textContent</a></code> или <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style">btn.style</a></code>), но оно относится к особому типу. Если вы установите его равным какому-нибудь коду, этот код будет запущен при возникновении события (при нажатии на кнопку).</p> + +<p>Для получения того же результата, Вы также можете присвоить свойству обработчика имя уже описанной функции (как мы видели в статье <a href="/ru/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Создайте свою функцию</a>):</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.onclick = bgChange;</pre> + +<p>Давайте теперь поэкспериментируем с другими свойствами обработчика событий.</p> + +<p>Создайте локальную копию файла <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerproperty.html">random-color-eventhandlerproperty.html</a> и откройте ее в своем браузере. Это всего лишь копия простого примера про случайные цвета, который мы уже разобрали в этой статье. Теперь попробуйте изменить <code>btn.onclick</code> на следующие значения и понаблюдайте за результатами:</p> + +<ul> + <li><code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onfocus">btn.onfocus</a></code> и <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onblur">btn.onblur</a></code> — Цвет изменится, когда кнопка будет сфокусирована или не сфокусирована (попробуйте нажать Tab, чтобы выбрать кнопку или убрать выбор). Эти свойства часто применяются для отображения информации о том, как заполнить поля формы, когда они сфокусированы, или отобразить сообщение об ошибке, если поле формы было заполнено с неправильным значением.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/ondblclick">btn.ondblclick</a></code> — Цвет будет изменяться только при двойном щелчке.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeypress">window.onkeypress</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeydown">window.onkeydown</a></code>, <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onkeyup">window.onkeyup</a></code> — Цвет будет меняться при нажатии клавиши на клавиатуре, причём <code>keypress</code> ссылается на обычное нажатие (нажатие кнопки и последующее её отпускание <em>как одно целое</em>), в то время как <code>keydown</code> и <code>keyup</code> <em>разделяют</em> действия на нажатие клавиши и отпускание, и ссылаются на них соответственно. Обратите внимание, что это не работает, если вы попытаетесь зарегистрировать этот обработчик событий на самой кнопке - его нужно зарегистрировать на объекте <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window">window</a>, который представляет все окно браузера.</li> + <li><code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseover">btn.onmouseover</a></code> и <code><a href="/en-US/docs/Web/API/GlobalEventHandlers/onmouseout">btn.onmouseout</a></code> — Цвет будет меняться при наведении указателя мыши на кнопку или когда указатель будет отводиться от кнопки соответственно.</li> +</ul> + +<p>Некоторые события очень общие и доступны практически в любом месте (например, обработчик <code>onclick</code> может быть зарегистрирован практически для любого элемента), тогда как некоторые из них более конкретны и полезны только в определенных ситуациях (например, имеет смысл использовать <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/GlobalEventHandlers.onplay">onplay</a> только для определенных элементов, таких как {{htmlelement ("video")}}).</p> + +<h3 id="Встроенные_обработчики_событий_-_не_используйте_их">Встроенные обработчики событий - не используйте их</h3> + +<p>Самый ранний из введенных в сеть Web методов регистрации <em>обработчиков событий</em> базируется на <strong>HTML атрибутах </strong>(<strong>встроенные обработчики событий</strong>):</p> + +<pre class="brush: html notranslate"><button onclick="bgChange()">Press me</button> +</pre> + +<pre class="brush: js notranslate">function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerattributes.html">полный исходник кода</a> из этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventhandlerattributes.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Значение атрибута — это буквально код JavaScript, который вы хотите запустить при возникновении события. В приведенном выше примере вызывается функция, определенная внутри элемента {{htmlelement ("script")}} на той же странице, но вы также можете вставить JavaScript непосредственно внутри атрибута, например:</p> + +<pre class="brush: html notranslate"><button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button></pre> + +<p>Для многих свойств обработчика событий существуют эквиваленты в виде атрибутов HTML. Однако, не рекомендуется их использовать — это считается плохой практикой. Использование атрибутов для регистрации обработчика событий кажется простым и быстрым методом, но такое описание обработчиков также скоро становится неудобным и неэффективным.</p> + +<p>Более того, не рекомендуется смешивать HTML и JavaScript файлы, так как в дальнейшем такой код становится сложнее с точки зрения обработки (парсинга). Лучше держать весь JavaScript в одном месте. Также, если он находится в отдельном файле, вы можете применить его к нескольким документам HTML.</p> + +<p>Даже при работе только в одном файле использование встроенных обработчиков не является хорошей идеей. Ладно, если у Вас одна кнопка, но что, если у вас их 100? Вам нужно добавить в файл 100 атрибутов; обслуживание такого кода очень быстро превратится в кошмар. С помощью JavaScript вы можете легко добавить функцию обработчика событий ко всем кнопкам на странице независимо от того, сколько их было.</p> + +<p>Например:</p> + +<pre class="brush: js notranslate">const buttons = document.querySelectorAll('button'); + +for (var i = 0; i < buttons.length; i++) { + buttons[i].onclick = bgChange; +}</pre> + +<p class="brush: js">Обратите внимание, что для перебора всех элементов, которые содержит объект <code><a href="/en-US/docs/Web/API/NodeList">NodeList</a></code>, можно воспользоваться встроенным методом <code><a href="/en-US/docs/Web/API/NodeList/forEach">forEach()</a></code>:</p> + +<pre class="brush: js notranslate">buttons.forEach(function(button) { + button.onclick = bgChange; +});</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Разделение логики Вашей программы и Вашего контента также делает Ваш сайт более дружественным к поисковым системам.</p> +</div> + +<h3 id="Функции_addEventListener_и_removeEventListener">Функции addEventListener() и removeEventListener()</h3> + +<p>Новый тип механизма событий определен в спецификации <a href="https://www.w3.org/TR/DOM-Level-2-Events/">Document Object Model (DOM) Level 2 Events</a>, которая предоставляет браузеру новую функцию — <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>. Работает она аналогично свойствам обработчика событий, но синтаксис совсем другой. Наш пример со случайным цветом мог бы выглядеть и так:</p> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); + +function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-addeventlistener.html">исходный код</a> из этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-addeventlistener.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Внутри функции <code>addEventListener()</code> мы указываем два параметра — имя события, для которого мы хотим зарегистрировать этот обработчик, и код, содержащий функцию обработчика, которую мы хотим запустить в ответ. Обратите внимание, что будет целесообразно поместить весь код внутри функции <code>addEventListener()</code> в анонимную функцию, например:</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', function() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +});</pre> + +<p>Этот механизм имеет некоторые преимущества по сравнению с более старыми механизмами, рассмотренными ранее. Например, существует аналогичная функция <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a></code>, которая удаляет ранее добавленный прослушиватель. Это приведет к удалению набора слушателей в первом блоке кода в этом разделе:</p> + +<pre class="brush: js notranslate">btn.removeEventListener('click', bgChange);</pre> + +<p>Это не важно для простых небольших программ, но для более крупных и более сложных программ он может повысить эффективность очистки старых неиспользуемых обработчиков событий. Кроме того, это позволяет вам иметь одну и ту же кнопку, выполняющую различные действия в разных обстоятельствах — все, что вам нужно сделать, это добавить/удалить обработчики событий, если это необходимо.</p> + +<p>Также, вы можете зарегистрировать несколько обработчиков для одного и того же прослушивателя. Следующие два обработчика не будут применяться:</p> + +<pre class="brush: js notranslate">myElement.onclick = functionA; +myElement.onclick = functionB;</pre> + +<p>Поскольку вторая строка будет перезаписывать значение <code>onclick</code>, установленное первой. Однако, если:</p> + +<pre class="brush: js notranslate">myElement.addEventListener('click', functionA); +myElement.addEventListener('click', functionB);</pre> + +<p>Обе функции будут выполняться при щелчке элемента.</p> + +<p>Кроме того, в этом механизме событий имеется ряд других мощных функций и опций. Эта тема выходит за рамки данной статьи, но если вы хотите изучить подробнее, переходите по ссылкам: <a href="/ru/docs/Web/API/EventTarget/addEventListener">Метод EventTarget.addEventListener()</a> и <a href="/ru/docs/Web/API/EventTarget/removeEventListener">Метод EventTarget.removeEventListener()</a>.</p> + +<h3 id="Какой_механизм_мне_использовать">Какой механизм мне использовать?</h3> + +<p>Из трех механизмов определенно не нужно использовать атрибуты событий HTML. Как упоминалось выше, это устаревшая и плохая практика.</p> + +<p>Остальные два являются относительно взаимозаменяемыми, по крайней мере для простых целей</p> + +<ul> + <li>Свойства обработчика событий имеют меньшую мощность и параметры, но лучше совместимость между браузерами (поддерживается еще в Internet Explorer 8). Вероятно, вам следует начать с них, когда вы учитесь.</li> + <li>События уровня 2 DOM (<code>addEventListener()</code> и т. д.) являются более мощными, но также могут стать более сложными и хуже поддерживаться (поддерживается еще в Internet Explorer 9). Вам также стоит поэкспериментировать с ними и стремиться использовать их там, где это возможно.</li> +</ul> + +<p>Основные преимущества третьего механизма заключаются в том, что при необходимости можно удалить код обработчика событий, используя <code>removeEventListener()</code>, и так же можно добавить несколько элементов-слушателей того же типа к элементам. Например, вы можете вызвать <code>addEventListener('click', function() {...})</code> для элемента несколько раз, с разными функциями, указанными во втором аргументе. Это невозможно при использовании свойств обработчика событий, поскольку любые последующие попытки установить свойство будут перезаписывать более ранние, например:</p> + +<pre class="brush: js notranslate">element.onclick = function1; +element.onclick = function2; +etc.</pre> + +<div class="note"> +<p><strong>Примечание:</strong> Если вам требуется поддержка браузеров старше Internet Explorer 8 в вашем проекте, вы можете столкнуться с трудностями, так как такие старые браузеры используют старые модели событий из более новых браузеров. Но не бойтесь, большинство библиотек JavaScript (например, <code>jQuery</code>) имеют встроенные функции, которые абстрагируют различия между браузерами. Не беспокойтесь об этом слишком много на этапе вашего учебного путешествия.</p> +</div> + +<h2 id="Другие_концепции_событий">Другие концепции событий</h2> + +<p>Рассмотрим некоторые современные концепции, имеющие отношение к событиям. На данный момент не обязательно понимать их полностью, но предстывление о них поможет лучше понять некоторые модели кода, с которыми вы, вероятно, столкнетесь.</p> + +<h3 id="Объекты_событий"> Объекты событий</h3> + +<p>Иногда внутри функции обработчика событий вы можете увидеть параметр, заданный с таким именем, как <code>event</code>, <code>evt</code> или просто <code>e</code>. Называется он <strong>объектом события</strong> и он автоматически передается обработчикам событий для предоставления дополнительных функций и информации. Например, давайте немного перепишем наш прмер со случайным цветом:</p> + +<pre class="brush: js notranslate">function bgChange(e) { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + e.target.style.backgroundColor = rndCol; + console.log(e); +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>Примечание</strong>: Вы можете найти <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventobject.html">исходник кода</a> для этого примера на GitHub (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventobject.html">взгляните на его выполнение</a>).</p> +</div> + +<p>Итак в коде выше мы включаем объект события <strong><code>e</code></strong> в функцию, а в функции — настройку стиля фона для <code>e.target</code>, который является кнопкой. Свойство объекта события <code>target</code> всегда является ссылкой на элемент, с которым только что произошло событие. Поэтому в этом примере мы устанавливаем случайный цвет фона на кнопке, а не на странице.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Вместо <code>e</code>/<code>evt</code>/<code>event</code> можно использовать любое имя для объекта события, которое затем можно использовать для ссылки на него в функции обработчика событий. <code>e</code>/<code>evt</code>/<code>event</code> чаще всего используются разработчиками, потому что они короткие и легко запоминаются. И хорошо придерживаться стандарта.</p> +</div> + +<p><code>e.target</code> применяют, когда нужно установить один и тот же обработчик событий на несколько элементов и, когда на них происходит событие, применить определенное действие к ним ко всем. Например, у вас может быть набор из 16 плиток, которые исчезают при нажатии. Полезно всегда иметь возможность просто указать, чтобы объект исчез, как <code>e.target</code>, вместо того, чтобы выбирать его более сложным способом. В следующем примере (см. исходный код на <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/useful-eventtarget.html">useful-eventtarget.html</a>,а как он работает можно посмотреть <a href="https://mdn.github.io/learning-area/javascript/building-blocks/events/useful-eventtarget.html">здесь</a>), мы создаем 16 элементов {{htmlelement ("div")}} с использованием JavaScript. Затем мы выберем все из них, используя {{domxref ("document.querySelectorAll()")}}, и с помощью цикла <code>for</code> выберем каждый из них, добавив обработчик <code>onclick</code> к каждому так, чтобы случайный цвет применялся к каждому клику:</p> + +<pre class="brush: js notranslate">var divs = document.querySelectorAll('div'); + +for (var i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } +}</pre> + +<p>Результат выглядит следующим образом (попробуйте щелкнуть по нему):</p> + +<div class="hidden"> +<h6 id="Hidden_example">Hidden example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Useful event target example</title> + <style> + div { + background-color: #ff6600; + height: 100px; + width: 25%; + float: left; + } + </style> + </head> + <body> + <script> + for (var i = 1; i <= 16; i++) { + var myDiv = document.createElement('div'); + document.body.appendChild(myDiv); + } + + function random(number) { + return Math.floor(Math.random()*number); + } + + function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + return rndCol; + } + + var divs = document.querySelectorAll('div'); + + for (var i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } + } + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 400) }}</p> + +<p>Большинство обработчиков событий, с которыми вы столкнулись, имеют только стандартный набор свойств и функций (методов), доступных для объекта события (см. {{domxref("Event")}} для ссылки на полный список). Однако некоторые более продвинутые обработчики добавляют специальные свойства, содержащие дополнительные данные, которые им необходимо выполнять. Например, <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder_API">Media Recorder API</a> имеет событие, доступное для данных, которое срабатывает, когда записано какое-либо аудио или видео и доступно для выполнения чего-либо (например, для сохранения или воспроизведения). Соответствующий объект события <a href="https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/ondataavailable">ondataavailable</a> handler имеет свойство данных, содержащее записанные аудио- или видеоданные, чтобы вы могли получить к нему доступ и что-то сделать с ним.</p> + +<h3 id="Предотвращение_поведения_по_умолчанию"> Предотвращение поведения по умолчанию</h3> + +<p>Иногда бывают ситуации, когда нужно остановить событие, выполняющее то, что оно делает по умолчанию. Наиболее распространенным примером является веб-форма, например, пользовательская форма регистрации. Когда вы вводите данные и нажимаете кнопку отправки, естественное поведение заключается в том, что данные должны быть отправлены на указанную страницу на сервере для обработки, а браузер перенаправлется на страницу с сообщением об успехе (или остаться на той же странице, если другое не указано).</p> + +<p>Но если пользователь отправил данные не правильно, как разработчик, вы хотите остановить отправку на сервер и выдать сообщение об ошибке с информацией о том, что не так и что нужно сделать. Некоторые браузеры поддерживают функции автоматической проверки данных формы, но, поскольку многие этого не делают, вам не следует полагаться на них и выполнять свои собственные проверки валидации. Давайте посмотрим на простой пример.</p> + +<p>Простая форма HTML, в которой требуется ввести ваше имя и фамилию:</p> + +<pre class="brush: html notranslate"><form> + <div> + <label for="fname">Имя: </label> + <input id="fname" type="text"> + </div> + <div> + <label for="lname">Фамилия: </label> + <input id="lname" type="text"> + </div> + <div> + <input id="submit" type="submit"> + </div> +</form> +<p></p></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">div { + margin-bottom: 10px; +} +</pre> +</div> + +<p>В JavaScript мы реализуем очень простую проверку внутри обработчика события <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onsubmit">onsubmit</a> (событие "отправить" запускается в форме, когда оно отправлено), который проверяет, пусты ли текстовые поля. Если они пусты, мы вызываем функцию <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code> объекта события, которая останавливает отправку формы, а затем выводит сообщение об ошибке в абзаце ниже нашей формы, чтобы сообщить пользователю, что не так:</p> + +<pre class="brush: js notranslate">var form = document.querySelector('form'); +var fname = document.getElementById('fname'); +var lname = document.getElementById('lname'); +var submit = document.getElementById('submit'); +var para = document.querySelector('p'); + +form.onsubmit = function(e) { + if (fname.value === '' || lname.value === '') { + e.preventDefault(); + para.textContent = 'Оба поля должны быть заполнены!'; + } +}</pre> + +<p>Очевидно, что это довольно слабая проверка формы - это не помешает пользователю отправить форму с пробелами или цифрами, введенными в поля, но для примера подходит. Вывод выглядит следующим образом:</p> + +<p>{{ EmbedLiveSample('Предотвращение_поведения_по_умолчанию', '100%', 140) }}</p> + +<div class="note"> +<p><strong>Примечание</strong>: чтобы увидеть исходный код, откройте <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/preventdefault-validation.html">preventdefault-validation.html</a> (также <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/preventdefault-validation.html">запустите</a> здесь).</p> +</div> + +<h3 id="Всплытие_и_перехват_событий">Всплытие и перехват событий</h3> + +<p>Последним предметом для рассмотрения в этой теме является то, с чем вы не часто будете сталкиваться, но это может стать настоящей головной болью, если вы не поймете, как работает следующий механизм. <em>Всплытие</em> и <em>перехват событий</em> — два механизма, описывающих, что происходит, когда два обработчика одного и того же события активируются на одном элементе. Посмотрим на пример. Чтобы сделать это проще — откройте пример <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> в одной вкладке и <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">исходный код </a>в другой вкладке. Он также представлен ниже:</p> + +<div class="hidden"> +<h6 id="Hidden_video_example">Hidden video example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Show video box example</title> + <style> + div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + width: 550px; + height: 420px; + border-radius: 10px; + background-color: #eee; + background-image: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.4)); + } + + .hidden { + left: -50%; + } + + .showing { + left: 50%; + } + + div video { + display: block; + width: 400px; + margin: 50px auto; + } + + </style> + </head> + <body> + <button>Display video</button> + + <div class="hidden"> + <video> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4" type="video/mp4"> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> + </div> + + <script> + + var btn = document.querySelector('button'); + var videoBox = document.querySelector('div'); + var video = document.querySelector('video'); + + btn.onclick = function() { + displayVideo(); + } + + function displayVideo() { + if(videoBox.getAttribute('class') === 'hidden') { + videoBox.setAttribute('class','showing'); + } + } + + videoBox.addEventListener('click',function() { + videoBox.setAttribute('class','hidden'); + }); + + video.addEventListener('click',function() { + video.play(); + }); + + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_video_example', '100%', 500) }}</p> + +<p>Это довольно простой пример, который показывает и скрывает {{htmlelement ("div")}} с элементом {{htmlelement ("video")}} внутри него:</p> + +<pre class="brush: html notranslate"><button>Display video</button> + +<div class="hidden"> + <video> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> +</div></pre> + +<p>При нажатии на кнопку {{htmlelement ("button")}}, изменяется атрибут класса элемента <code><div></code> с <code>hidden</code> на <code>showing</code> (CSS примера содержит эти два класса, которые размещают блок вне экрана и на экране соответственно):</p> + +<pre class="brush: css notranslate">div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + ... + } +<font color="#6f42c1" face="SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace">.hidden { + left: -50%; + } +.showing { + left: 50%; + }</font></pre> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); +btn.onclick = function() { + videoBox.setAttribute('class', 'showing'); +}</pre> + +<p>Затем мы добавляем еще пару обработчиков событий <code>onclick.</code> Первый к <code><div></code>, а второй к <code><video></code>. Идея заключается в том, чтобы при щелчке по области <code><div></code> вне зоны видео поле снова скрылось, а при клике в области <code><video></code> видео начало воспроизводиться.</p> + +<pre class="brush: js notranslate">var videoBox = document.querySelector('div'); +var video = document.querySelector('video'); + +videoBox.onclick = function() { + videoBox.setAttribute('class', 'hidden'); +}; + +video.onclick = function() { + video.play(); +};</pre> + +<p>Но есть проблема: когда вы нажимаете на видео, оно начинает воспроизводиться, но одновременно вызывает скрытие <code><div></code>. Это связано с тем, что видео находится внутри <code><div>,</code> это часть его, поэтому нажатие на видео фактически запускает оба вышеуказанных обработчика событий.</p> + +<h4 id="Всплытие_и_перехват_событий_—_концепция_выполнения"><strong>Всплытие и перехват событий — концепция выполнения</strong></h4> + +<p>Когда событие инициируется элементом, который имеет родительские элементы (например, {{htmlelement ("video")}} в нашем случае), современные браузеры выполняют две разные фазы — фазу <strong>захвата</strong> и фазу <strong>всплытия</strong>.</p> + +<p>На стадии <strong>захвата </strong>происходит следующее:</p> + +<ul> + <li>Браузер проверяет, имеет ли самый внешний элемент ({{htmlelement ("html")}}) обработчик события <code>onclick</code>, зарегистрированный на нем на этапе захвата и запускает его, если это так.</li> + <li>Затем он переходит к следующему элементу внутри <code><html></code> и выполняет то же самое, затем следующее и так далее, пока не достигнет элемента, на который на самом деле нажали.</li> +</ul> + +<p>На стадии <strong>всплытия</strong> происходит полная противоположность:</p> + +<ul> + <li>Браузер проверяет, имеет ли элемент, который был фактически нажат, обработчик события <code>onclick</code>, зарегистрированный на нем в фазе высплытия, и запускает его, если это так.</li> + <li>Затем он переходит к следующему непосредственному родительскому элементу и выполняет то же самое, затем следующее и так далее, пока не достигнет элемента <code><html></code>.</li> +</ul> + +<p><a href="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png"><img alt="" src="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png" style="display: block; height: 452px; margin: 0px auto; width: 960px;"></a></p> + +<p>(Нажмите на изображение, чтобы увеличить диаграмму)</p> + +<p>В современных браузерах по умолчанию все обработчики событий регистрируются в фазе <strong><em>всплытия</em></strong>. Итак, в нашем текущем примере, когда вы нажимаете видео, событие click вызывается из элемента <code><video></code> наружу, в элемент <code><html></code>. По пути:</p> + +<ul> + <li>Он находит обработчик <code>video.onclick...</code> и запускает его, поэтому видео сначала начинает воспроизводиться.</li> + <li>Затем он находит обработчик <code>videoBox.onclick...</code> и запускает его, поэтому видео также скрывается.</li> +</ul> + +<h4 id="Исправление_проблемы_с_помощью_stopPropagation">Исправление проблемы с помощью stopPropagation()</h4> + +<p>Чтобы исправить это раздражающее поведение, стандартный объект события имеет функцию, называемую <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation">stopPropagation()</a></code>, которая при вызове в обработчике событий объекта делает так, чтобы обработчик выполнялся, но событие не всплывало дальше по цепочке, поэтому не будут запускаться другие обработчики.</p> + +<p>Поэтому мы можем исправить нашу текущую проблему, изменив вторую функцию-обработчик в предыдущем блоке кода:</p> + +<pre class="brush: js notranslate">video.onclick = function(e) { + e.stopPropagation(); + video.play(); +};</pre> + +<p>Вы можете попробовать создать локальную копию <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> и попробовать его самостоятельно исправить или просмотреть исправленный результат в <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html">show-video-box-fixed.html</a> (также см. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box-fixed.html">исходный код здесь</a>).</p> + +<div class="note"><strong>Примечание</strong>: Зачем беспокоиться как с захватом, так и с всплыванием? Что ж, в старые добрые времена, когда браузеры были менее совместимы, чем сейчас, Netscape использовал только захват событий, а Internet Explorer использовал только всплывающие события. Когда W3C решил попытаться стандартизировать поведение и достичь консенсуса, они в итоге получили эту систему, которая включала в себя и то, и другое, что реализовано в одном из современных браузеров.</div> + +<div class="note"> +<p><strong>Примечание</strong>: Как упоминалось выше, по умолчанию все обработчики событий регистрируются в фазе всплытия и это имеет смысл в большинстве случаев. Если вы действительно хотите зарегистрировать событие в фазе захвата, вы можете сделать это, зарегистрировав обработчик с помощью <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code> и установив для третьего дополнительного свойства значение <code>true</code>.</p> +</div> + +<h4 id="Делегирование_события"><strong>Делегирование</strong> события</h4> + +<p>Всплытие также позволяет нам использовать <strong>делегирование событий. </strong> Если у какого-либо родительского элемента есть множество дочерних элементов, и вы хотите, чтобы определенный код выполнялся при щелчке (событии) на каждом из дочерних элементов, можно установить прослушиватель событий на родительском элементе и события, происходящие на дочерних элементах будут всплывать до их родителя. При этом не нужно устанавливать прослушивателя событий на каждом дочернем элементе.</p> + +<p>Хорошим примером является серия элементов списка. Если вы хотите, чтобы каждый из них, например, отображал сообщение при нажатии, вы можете установить прослушиватель событий <code>click</code> для родительского элемента <code><ul></code> и он будет всплывать в элементах списка.</p> + +<p>Эту концепцию объясняет в своем блоге Дэвид Уолш, где приводит несколько примеров. (см. <a href="https://davidwalsh.name/event-delegate">How JavaScript Event Delegation Works</a>.)</p> + +<h2 id="Вывод">Вывод</h2> + +<p>Это все, что вам нужно знать о веб-событиях на этом этапе. Как уже упоминалось, события не являются частью основного JavaScript — они определены в веб-интерфейсах браузера (<a href="/ru/docs/Web/API">Web API</a>).</p> + +<p>Кроме того, важно понимать, что различные контексты, в которых используется JavaScript, обычно имеют разные модели событий — от веб-API до других областей, таких как браузерные WebExtensions и Node.js (серверный JavaScript). Может сейчас вы не особо в этом разбираетесь, но по мере изучения веб-разработки начнет приходить более ясное понимание тематики.</p> + +<p>Если у вас возникли вопросы, попробуйте прочесть статью снова или <a href="https://developer.mozilla.org/en-US/docs/Learn#Contact_us">обратитесь за помощью к нам</a>.</p> + +<h2 id="См._также">См. также</h2> + +<ul> + <li><a href="http://www.quirksmode.org/js/events_order.html">Event order</a> (обсуждение захвата и всплытий) — превосходно детализированная часть от Peter-Paul Koch.</li> + <li><a href="http://www.quirksmode.org/js/events_access.html">Event accessing</a> (discussing of the event object) — another excellently detailed piece by Peter-Paul Koch.</li> + <li><a href="/en-US/docs/Web/Events">Event reference</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "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> + +<div class="s3gt_translate_tooltip_mini_box" id="s3gt_translate_tooltip_mini" style="background: initial !important; border: initial !important; border-radius: initial !important; border-collapse: initial !important; direction: ltr !important; font-weight: initial !important; height: initial !important; letter-spacing: initial !important; max-width: initial !important; min-height: initial !important; margin: auto !important; outline: initial !important; padding: initial !important; position: absolute; text-align: initial !important; text-shadow: initial !important; width: initial !important; display: initial !important; color: inherit !important; font-size: 13px !important; font-family: X-LocaleSpecific, sans-serif, Tahoma, Helvetica !important; line-height: 13px !important; vertical-align: top !important; white-space: inherit !important; left: 416px; top: 2989px; opacity: 0.35;"> +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_sound" style="width: 12px; height: 12px; border-radius: 4px;" title="Прослушать"></div> + +<div class="s3gt_translate_tooltip_mini" id="s3gt_translate_tooltip_mini_copy" style="width: 12px; height: 12px; border-radius: 4px;" title="Скопировать текст в буфер обмена"></div> +</div> |
