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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
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>
|