1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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>
|