aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/functions/index.html
blob: 2bdc3496e17f1fa53404d3fcf1af2ac663909a49 (plain)
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
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
---
title: Функции
slug: Web/JavaScript/Reference/Functions
tags:
  - Функции
  - Функция
translation_of: Web/JavaScript/Reference/Functions
---
<div>{{jsSidebar("Functions")}}</div>

<h2 id="Summary" name="Summary">Сводка</h2>

<p>В общем случае, функция — это "подпрограмма", которую можно <em>вызывать</em> из внешнего (или внутреннего, в случае рекурсии) по отношению к функции кода. Как и сама программа, функция состоит из последовательности инструкций, называемой <em>телом функции.</em> Значения могут быть <em>переданы</em> в функцию, а функция <em>вернёт</em> значение.</p>

<p>В JavaScript функции являются объектами первого класса, то есть: они являются объектами и с ними можно взаимодействовать и передавать их точно так же как любой другой объект. Если быть точным, функции — это объекты <code><a href="ru/docs/Web/JavaScript/Reference/Global_Objects/Function">Function</a></code>.</p>

<p>Больше подробностей и примеров можно найти в <a href="/ru/docs/Web/JavaScript/Guide/Functions">руководстве по функциям в JavaScript</a>.</p>

<h2 id="Описание">Описание</h2>

<p>Каждая функция в JavaScript — это объект Function.  О свойствах и методах объектов Function можно прочитать в статье {{jsxref("Function")}}.</p>

<p>Функции — это не процедуры. Функция всегда возвращает значение, а процедура может возвращать, а может не возвращать.</p>

<p>Чтобы вернуть значение, отличное от значения по умолчанию, в функции должна быть инструкция <code><a href="/ru/docs/Web/JavaScript/Reference/Statements/return">return</a></code>, которая указывает, что именно нужно вернуть. Функция без него вернёт значение по умолчанию. В случае <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">конструктора</a>, вызванного с ключевым словом <code><a href="/ru/docs/Web/JavaScript/Reference/Operators/new">new</a>, </code>значение по умолчанию — это значение его параметра <code>this</code>. Для остальных функций значением по умолчанию будет <code>undefined</code>.</p>

<p>Параметры вызова функции называются <em>аргументами</em> функции. Аргументы передаются в функцию <em>по значению</em>. Если функция изменяет значение аргумента, это изменение не отражается на глобальном состоянии или вызывающей функции. Однако ссылки на объекты — это тоже значения, и они отличаются тем, что если функция изменяет свойства объекта по ссылке, это изменение видно снаружи функции, как показано в примере ниже.</p>

<pre class="brush: js">/* Объявляем функцию 'myFunc' */
function myFunc(theObject) {
   theObject.brand = "Toyota";
 }

 /*
  * Объявляем переменную 'mycar';
  * создаём и инициализируем новый Object;
  * приравниваем 'mycar' к ссылке на него
  */
 var mycar = {
   brand: "Honda",
   model: "Accord",
   year: 1998
 };

 /* Выведет 'Honda' */
 console.log(mycar.brand);

 /* Передаём ссылку на объект в функцию */
 myFunc(mycar);

 /*
  * Выведет 'Toyota', так как значение свойства 'brand'
  * было изменено внутри функции.
  */
 console.log(mycar.brand);
</pre>

<p><a href="/ru/docs/Web/JavaScript/Reference/Operators/this"><code>Ключевое слово this</code></a> не ссылается на функцию, которая выполняется в данный момент, поэтому вы должны обращаться к объектами Function по имени, даже внутри тела самой функции.</p>

<h2 id="Defining_functions" name="Defining_functions">Определение функций</h2>

<p>Есть несколько способов определить функцию:</p>

<h3 id="The_function_declaration_.28function_statement.29" name="The_function_declaration_.28function_statement.29">Объявление функции (инструкция <code>function</code>)</h3>

<p>Специальный синтаксис для объявления функций (более подробно: <a href="/ru/docs/Web/JavaScript/Reference/Statements/function">function statement</a>):</p>

<pre>function <em>name</em>([<em>param</em>[, <em>param</em>[, ... <em>param</em>]]]) {
   <em>statements</em>
}
</pre>

<dl>
 <dt><code>name</code></dt>
 <dd>Имя функции.</dd>
</dl>

<dl>
 <dt><code>param</code></dt>
 <dd>Имя аргумента, передаваемого в функцию. У функции может быть не более 255 аргументов.</dd>
</dl>

<dl>
 <dt><code>statements</code></dt>
 <dd>Инструкции, из которых состоит тело функции.</dd>
</dl>

<h3 id="The_function_expression_.28function_operator.29" name="The_function_expression_.28function_operator.29">Функция-выражение (оператор <code>function</code>)</h3>

<p>Функция-выражение похожа на определение функции и имеет такой же синтаксис (более подробно: <a href="/ru/docs/Web/JavaScript/Reference/Operators/function">function operator</a>):</p>

<pre>function [<em>name</em>]([<em>param</em>] [, <em>param</em>] [..., <em>param</em>]) {
   <em>statements</em>
}
</pre>

<dl>
 <dt><code>name</code></dt>
 <dd>Имя функции. Может быть не указано, в таком случае функция становится анонимной.</dd>
</dl>

<dl>
 <dt><code>param</code></dt>
 <dd>Имя аргумента, передаваемого в функцию. У функции может быть не более 255 аргументов.</dd>
 <dt><code>statements</code></dt>
 <dd>Инструкции, из которых состоит тело функции.</dd>
</dl>

<h3 id="Стрелочная_функция-выражение_(>)">Стрелочная функция-выражение (=&gt;)</h3>

<div class="note">
<p><strong>Примечание:</strong> стрелочные функции являются экспериментальной технологией<em>,</em> частью спецификации ECMAScript 6 и пока что не поддерживаются всеми браузерами.</p>
</div>

<p>Стрелочные функции отличаются более кратким синтаксисом и тем, что они лексически связывают значение своего <code>this (подробнее об этом в статье <a href="/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Стрелочные функции</a>):</code></p>

<pre>([param] [, param]) =&gt; {
   statements
}

param =&gt; expression
</pre>

<dl>
 <dt><code>param</code></dt>
 <dd>Имя параметра. Если параметров нет, вместо них нужно поставить (). Если параметров больше одного, их также нужно заключить в ().</dd>
 <dt><code>statements or expression</code></dt>
 <dd>Если инструкций несколько, их нужно заключить в {}. Для одного выражения фигурных скобок не требуется, а результат этого выражения будет возвращён функцией (то есть<code> функция x =&gt; 3 + 8 вернёт 11).</code><code> </code></dd>
</dl>

<h3 id="The_Function_constructor" name="The_Function_constructor">Конструктор <code>Function</code></h3>

<div class="note">
<p><strong>Примечание:</strong> Использовать конструктор Function не рекомендуется, так как он принимает тело функции в виде строки, а это может помешать оптимизациям, которые выполняют движки JavaScript, а также привести к другим проблемам.</p>
</div>

<p>Объекты {{jsxref("Function")}} можно создавать с помощью оператора <code>new </code>(как и любые другие объекты):</p>

<pre>new Function (<em>arg1</em>, <em>arg2</em>, ... <em>argN</em>, <em>functionBody</em>)
</pre>

<dl>
 <dt><code>arg1, arg2, ... arg<em>N</em></code></dt>
 <dd>Ноль или больше имён параметров функции. Имя должно быть строкой, содержащей валидный идентификатор JavaScript. Если параметров несколько, они должны быть разделены запятыми. Например: "<code>x</code>", "<code>theValue</code>", или "<code>a,b</code>".</dd>
</dl>

<dl>
 <dt><code>functionBody</code></dt>
 <dd>Инструкции, из которых состоит тело функции.</dd>
</dl>

<p>Конструктор <code>Function</code> можно вызывать и без оператора <code>new,</code> эффект будет тем же.</p>

<h2 id="Параметры_функции">Параметры функции</h2>

<div class="note">
<p><strong>Примечание:</strong> Оставшиеся параметры и параметры по умолчанию <em>— это экспериментальная </em>технология, часть спецификации ECMAScript 6, и они пока ещё не получили широкой поддержки среди браузеров.</p>
</div>

<h3 id="Параметры_по_умолчанию">Параметры по умолчанию</h3>

<p>Параметры функции по умолчанию позволяют инициализировать формальные параметры со значениями по умолчанию, если им не было передано значение, или было передано <code>undefined</code>. Подробнее о них можно узнать в статье <a href="/ru/docs/Web/JavaScript/Reference/Functions/Default_parameters">Параметры по умолчанию</a>.</p>

<h3 id="Оставшиеся_параметры">Оставшиеся параметры</h3>

<p>Синтаксис оставшихся параметров позволяет передать бесконечное число аргументов как массив. Подробности можно найти в статье <a href="/ru/docs/Web/JavaScript/Reference/Functions/rest_parameters">Оставшиеся параметры</a>.</p>

<h2 id="The_arguments_object" name="The_arguments_object">Объект <code>arguments</code></h2>

<p>Внутри функции получить доступ к её аргументам можно через объект <a href="/ru/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>.</p>

<ul>
 <li><code><a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments">arguments</a></code>: Объект, похожий на массив и содержащий все аргументы, переданные в текущую функцию.</li>
 <li><code><a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/callee">arguments.callee</a></code> {{Deprecated_inline}}: Функция, исполняемая в текущий момент.</li>
 <li><code><a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/caller">arguments.caller</a></code> {{Obsolete_inline}} : Функция, которая вызвала текущую функцию.</li>
 <li><code><a href="/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments/length">arguments.length</a></code>: Число аргументов, переданных в функцию.</li>
</ul>

<h2 id="Определение_методов">Определение методов</h2>

<h3 id="Геттеры_и_сеттеры">Геттеры и сеттеры</h3>

<p>Можно определять геттеры (методы для чтения) и сеттеры (методы для изменения) для любого встроенного или пользовательского объекта, который поддерживает добавление новых свойств. Для этого используется синтаксис литерала объекта.</p>

<dl>
 <dt><a href="/en-US/docs/Web/JavaScript/Reference/Functions/get">get</a></dt>
 <dd>Связывает свойство объекта с функцией, которая будет вызвана при обращении к свойству.</dd>
 <dt><a href="/en-US/docs/Web/JavaScript/Reference/Functions/set">set</a></dt>
 <dd>Связывает свойство объекта с функцией, которая будет вызвана при попытке изменения свойства.</dd>
</dl>

<h3 id="Синтаксис_определения_методов">Синтаксис определения методов</h3>

<div class="note">
<p><strong>Примечание:</strong> <em>Определение методов — это экспериментальная </em>технология, часть спецификации ECMAScript 6, и она пока ещё не получила широкой поддержки среди браузеров.</p>
</div>

<p>Начиная с ECMAScript 6, можно определять собственные методы, используют более краткий синтаксис, похожий на геттеры и сеттеры. Более подробно  — в статье <a href="/ru/docs/Web/JavaScript/Reference/Functions/Method_definitions">Определение методов.</a></p>

<pre class="brush: js">var obj = {
  foo() {},
  bar() {}
};</pre>

<h2 id="Function_constructor_vs._function_declaration_vs._function_expression" name="Function_constructor_vs._function_declaration_vs._function_expression">Сравнение конструкторов <code>Function</code> с объявлением функций и функциями-выражениями</h2>

<p>Посмотрите на следующие примеры:</p>

<p>Функция, определённая через конструктор <code>Function</code> и приравненная к переменной <code>multiply:</code></p>

<pre class="brush: js">var multiply = new Function("x", "y", "return x * y");</pre>

<p>Объявление функции multiply:</p>

<pre class="brush: js">function multiply(x, y) {
   return x * y;
}
</pre>

<p>Анонимная функция-выражение, приравненная к переменной<code> multiply:</code></p>

<pre class="brush: js">var multiply = function(x, y) {
   return x * y;
};
</pre>

<p><em>Функция-выражение</em> с именем <code>func_name</code>, приравненное к переменной<code> multiply:</code></p>

<pre class="brush: js">var multiply = function func_name(x, y) {
   return x * y;
};
</pre>

<h3 id="Отличия">Отличия</h3>

<p>Во всех случаях результат примерно одинаков, но есть несколько нюансов:</p>

<p>Имя функции и переменная, к которой функция приравнена — это не одно и то же. Имя функции нельзя менять, а вот переменной, к которой приравнена функция, можно дать другое значение. В случае функции-выражения с именем, это имя может быть использовано только внутри самой функции. При попытке использовать его снаружи возникнет ошибка (а если ранее была объявлена переменная с таким именем, будет возвращено <code>undefined</code>). Например:</p>

<pre class="brush: js">var y = function x() {};
alert(x); // выкинет ошибку
</pre>

<p>Также имя функции-выражения проявляется, если сериализовать функцию через метод <a href="/ru/docs/Web/JavaScript/Reference/Global_Objects/Function/toString">Function.toString.</a></p>

<p>А вот переменная, к которой функция приравнена, ограничена только собственной областью видимости, которая включает ту область, где функция была объявлена.</p>

<p>Как показано в четвёртом примере, имя функции может отличаться от имени переменной, к которой функция приравнена, эти имена никак не связаны. Объявление функции (function declaration) также создаёт и переменную с именем, аналогичным имени функции. Таким образом:</p>

<ol>
 <li>Если функция определена с помощью функции-выражения (function expression), её имя доступно только внутри самой функции.</li>
 <li>Если функция объявлена (function declaration), её имя доступно в той области видимости, где функция была определена.</li>
</ol>

<p>У функции, определённой с помощью '<code>new Function'</code>, нет имени.  Однако, в JavaScript движке <a href="/en-US/docs/Mozilla/Projects/SpiderMonkey">SpiderMonkey</a>, сериализованное представление функции отображается так, как будто оно имеет имя "anonymous". Например, , <code>alert(new Function())</code> выдаст:</p>

<pre class="brush: js">function anonymous() {
}
</pre>

<p>Так как на самом деле у функции нет имени, переменную <code>anonymous</code> нельзя использовать внутри функции. Например, следующий пример выкинет ошибку:</p>

<pre class="brush: js">var foo = new Function("alert(anonymous);");
foo();
</pre>

<p>В отличии от функций, определённых через функцию-выражение или конструктор <code>Function</code>, функция, определённая через объявление, может быть использована перед тем, как была определена. Например:</p>

<pre class="brush: js">foo(); // выведет FOO!
function foo() {
   alert('FOO!');
}
</pre>

<p>Функция, определённая через функцию-выражение, наследует текущую область видимости, то есть создаёт замыкание. А вот функция, созданная с помощью конструктора <code>Function</code>, не наследует ничего, кроме глобальной области видимости (её наследуют вообще все функции).</p>

<p>Функции, определённые через функцию-выражение и объявление функции парсятся только один раз, в отличии от функций, созданных с помощью конструктора. То есть строка, которая передаётся в конструктор <code>Function</code>, парсится при каждом вызове конструктора. И хотя функция-выражение каждый раз создаёт замыкание, тело функции при этом не парсится, и получается, что функции-выражение всё равно быстрее, чем "<code>new Function(...)</code>". Поэтому конструктора <code>Function</code> в большинстве случаев стоит избегать, если это возможно.</p>

<p>Стоит отметить, что функции-выражения и объявления функций внутри функции, созданной при парсинге конструктора <code>Function</code>, парсятся только один раз. Например:</p>

<pre class="brush: js">var foo = (new Function("var bar = \'FOO!\';\nreturn(function() {\n\talert(bar);\n});"))();
foo(); //  "function() {\n\talert(bar);\n}" Эта часть строки, составляющей тело функции, не парсится во второй раз.</pre>

<p>Объявление функции можно очень легко (и часто случайно) превратить в функцию-выражение. Объявление функции перестаёт быть таковым, если оно:</p>

<ul>
 <li>становится частью выражения</li>
 <li>не является "исходным элементом" функции или файла. Исходный элемент  - это не вложенный элемент внутри функции или скрипта:</li>
</ul>

<pre class="brush: js">var x = 0;               // исходный элемент
if (x == 0) {            // исходный элемент
   x = 10;               // не исходный элемент
   function boo() {}     // не исходный элемент
}
function foo() {         // исходный элемент
   var y = 20;           // исходный элемент
   function bar() {}     // исходный элемент
   while (y == 10) {     // исходный элемент
      function blah() {} // не исходный элемент
      y++;               // не исходный элемент
   }
}
</pre>

<h3 id="Примеры">Примеры</h3>

<pre class="brush: js">// объявление функции
function foo() {}

// функция-выражение
(function bar() {})

// функция-выражение
x = function hello() {}


if (x) {
   // функция-выражение
   function world() {}
}


// объявление функции
function a() {
   // объявление функции
   function b() {}
   if (0) {
      // функция-выражение
      function c() {}
   }
}
</pre>

<h2 id="Conditionally_defining_a_function" name="Conditionally_defining_a_function">Определение функции в зависимости от условия</h2>

<p>Функции могут быть определены в зависимости от условий с помощью инструкции <code>function (разрешённое расширение стандарта</code> <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMA-262 Edition 3</a>) или конструктора <code>Function</code>. Обратите внимание, что подобные инструкции <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=609832">запрещены в ES5 strict</a>. Кроме того, эта возможность по-разному ведёт себя в разных браузерах, поэтому не стоит на неё рассчитывать.</p>

<p>В коде ниже функция <code>zero</code> никогда не будет определена и не может быть вызвана, потому что '<code>if (0)</code>' всегда расценивается как <code>false</code>:</p>

<pre class="brush: js">if (0) {
   function zero() {
      document.writeln("This is zero.");
   }
}
</pre>

<p>Если изменить условие на  '<code>if (1)</code>', функция <code>zero</code> будет определена.</p>

<p>Заметьте, что хотя это выглядит как объявление функции, на самом деле, это функция-выражение (или инструкция), так как она вложена внутрь другой инструкции. Изучите разницу между объявлением функции и функцией-выражением.</p>

<p>Некоторые JavaScript-движки (но не <a href="/en-US/docs/SpiderMonkey">SpiderMonkey</a>), неверно считают любую функцию-выражение с именем за объявление функции. Это приводит к тому, что функция <code>zero</code> будет определена, даже если условие всегда <code>false</code>. Более безопасный способ определить функцию по условию - это сделать её анонимной и приравнять к переменной:</p>

<pre class="brush: js">if (0) {
   var zero = function() {
      document.writeln("This is zero.");
   }
}
</pre>

<h2 id="Examples" name="Examples">Примеры</h2>

<h3 id="Example:_Returning_a_formatted_number" name="Example:_Returning_a_formatted_number">Пример: возврат отформатированного числа</h3>

<p>Эта функция возвращает строку, содержащую число с заданным количеством нулей перед ним:</p>

<pre class="brush: js">function padZeros(num, totalLen) {
   var numStr = num.toString();             // Инициализировать возвращаемое значение в виде строки
   var numZeros = totalLen - numStr.length; // Посчитать число нулей в начале
   for (var i = 1; i &lt;= numZeros; i++) {
      numStr = "0" + numStr;
   }
   return numStr;
}
</pre>

<p>Вызовем <code>padZeros</code>:</p>

<pre class="brush: js">var result;
result = padZeros(42,4); // возвращает "0042"
result = padZeros(42,2); // возвращает "42"
result = padZeros(5,4);  // возвращает "0005"
</pre>

<h3 id="Example:_Determining_whether_a_function_exists" name="Example:_Determining_whether_a_function_exists">Пример: существует ли функция</h3>

<p>Можно определить, существует ли функция с помощью оператора <code>typeof</code>. В следующем примере проверяется, есть ли у объекта <code>window</code> функция <code>noFunc</code>. Если есть, то она вызывается; если нет, выполняется какое-то другое действие.</p>

<pre class="brush: js"> if ('function' == typeof window.noFunc) {
   // вызывать noFunc()
 } else {
   // сделать что-то другое
 }
</pre>

<p>Заметьте, что в проверке условия используется ссылка на <code>noFunc</code> — после имени функции нет скобок, поэтому сама функция не вызывается.</p>

<h2 id="Спецификации">Спецификации</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Спецификация</th>
   <th scope="col">Статус</th>
   <th scope="col">Комментарий</th>
  </tr>
  <tr>
   <td>ECMAScript 1st Edition.</td>
   <td>Стандарт</td>
   <td>Изначальное определение. Релизовано в JavaScript 1.0</td>
  </tr>
  <tr>
   <td>{{SpecName('ES5.1', '#sec-13', 'Function Definition')}}</td>
   <td>{{Spec2('ES5.1')}}</td>
   <td> </td>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-function-definitions', 'Function definitions')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td>Новое: стрелочные функции, генераторы, параметры по умолчанию, оставшиеся параметры</td>
  </tr>
 </tbody>
</table>

<h2 id="Поддержка_браузерами">Поддержка браузерами</h2>

<p>{{Compat}}</p>

<h2 id="See_also" name="See_also">Смотрите также</h2>

<ul>
 <li><a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Function"><code>Function</code></a></li>
 <li><a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/function">Инструкция<code> function</code></a></li>
 <li><a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Operators/function">Оператор<code> function</code></a></li>
</ul>