Skip to content

Commit d813c3d

Browse files
committed
works
1 parent 3dc3018 commit d813c3d

File tree

1 file changed

+20
-274
lines changed
  • 1-js/2-first-steps/20-function-parameters

1 file changed

+20
-274
lines changed

1-js/2-first-steps/20-function-parameters/article.md

Lines changed: 20 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -237,304 +237,50 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
237237

238238
## The spread operator
239239

240-
// TODO!!!
240+
As we've seen before, the rest operator `...` allows to gather parameters in the array.
241241

242-
Выше мы увидели использование `...` для чтения параметров в объявлении функции. Но этот же оператор можно использовать и при вызове функции, для передачи массива параметров как списка, например:
242+
But there's a reverse named "the spread operator". It also looks like `...` and works at call-time.
243243

244-
```js run
245-
'use strict';
246-
247-
let numbers = [2, 3, 15];
248-
249-
// Оператор ... в вызове передаст массив как список аргументов
250-
// Этот вызов аналогичен Math.max(2, 3, 15)
251-
let max = Math.max(*!*...numbers*/!*);
252-
253-
alert( max ); // 15
254-
```
255-
256-
Формально говоря, эти два вызова делают одно и то же:
257-
258-
```js
259-
Math.max(...numbers);
260-
Math.max.apply(Math, numbers);
261-
```
262-
263-
Похоже, что первый -- короче и красивее.
264-
265-
## Деструктуризация в параметрах
266-
267-
268-
## Имя "name"
269-
270-
В свойстве `name` у функции находится её имя.
271-
272-
Например:
244+
The spread operator allows to "unfurl" an array into a list of parameters, like this:
273245

274246
```js run
275-
'use strict';
276-
277-
function f() {} // f.name == "f"
278-
279-
let g = function g() {}; // g.name == "g"
280-
281-
alert(f.name + ' ' + g.name) // f g
282-
```
283-
284-
В примере выше показаны Function Declaration и Named Function Expression. В синтаксисе выше довольно очевидно, что у этих функций есть имя `name`. В конце концов, оно указано в объявлении.
285-
286-
Но современный JavaScript идёт дальше, он старается даже анонимным функциям дать разумные имена.
287-
288-
Например, при создании анонимной функции с одновременной записью в переменную или свойство -- её имя равно названию переменной (или свойства).
289-
290-
Например:
291-
292-
```js
293-
'use strict';
294-
295-
// свойство g.name = "g"
296-
let g = function() {};
297-
298-
let user = {
299-
// свойство user.sayHi.name == "sayHi"
300-
sayHi: function() {}
301-
};
302-
```
303-
304-
## Функции в блоке
305-
306-
Объявление функции Function Declaration, сделанное в блоке, видно только в этом блоке.
307-
308-
Например:
309-
310-
```js run
311-
'use strict';
312-
313-
if (true) {
314-
315-
sayHi(); // работает
316-
317-
function sayHi() {
318-
alert("Привет!");
319-
}
247+
let fullName = ["Gaius", "Julius", "Caesar"];
320248

249+
function showName(firstName, secondName, lastName) {
250+
alert(firstName);
251+
alert(secondName);
252+
alert(lastName);
321253
}
322-
sayHi(); // ошибка, функции не существует
323-
```
324-
325-
То есть, иными словами, такое объявление -- ведёт себя в точности как если бы `let sayHi = function() {…}` было сделано в начале блока.
326-
327-
## Функции через =>
328-
329-
Появился новый синтаксис для задания функций через "стрелку" `=>`.
330-
331-
Его простейший вариант выглядит так:
332-
```js run
333-
'use strict';
334254

335-
*!*
336-
let inc = x => x+1;
337-
*/!*
338-
339-
alert( inc(1) ); // 2
255+
// The spread operator ... passes an array as a list of arguments
256+
showName(...fullName);
340257
```
341258

342-
Эти две записи -- примерно аналогичны:
343-
344-
```js
345-
let inc = x => x+1;
346-
347-
let inc = function(x) { return x + 1; };
348-
```
349259

350-
Как видно, `"x => x+1"` -- это уже готовая функция. Слева от `=>` находится аргумент, а справа -- выражение, которое нужно вернуть.
260+
Let's see a more real-life example.
351261

352-
Если аргументов несколько, то нужно обернуть их в скобки, вот так:
262+
There exist a built-in function [Math.max](mdn:js/Math/max) that takes a list of values and returns the greatest one:
353263

354264
```js run
355-
'use strict';
356-
357-
*!*
358-
let sum = (a,b) => a + b;
359-
*/!*
360-
361-
// аналог с function
362-
// let inc = function(a, b) { return a + b; };
363-
364-
alert( sum(1, 2) ); // 3
265+
alert( Math.max(5, 7, -8, 1) ); // 7
365266
```
366267

367-
Если нужно задать функцию без аргументов, то также используются скобки, в этом случае -- пустые:
268+
Imagine we have an array and want to select a maximum from it. Unfortunately, `Math.max` works with a list of parameters, not with arrays, so a direct call `Math.max(arr)` won't work. But we can use the spread operator `...` to pass the array as the list:
368269

369-
```js run
370-
'use strict';
371-
372-
*!*
373-
// вызов getTime() будет возвращать текущее время
374-
let getTime = () => new Date().getHours() + ':' + new Date().getMinutes();
375-
*/!*
376-
377-
alert( getTime() ); // текущее время
378-
```
379-
380-
Когда тело функции достаточно большое, то можно его обернуть в фигурные скобки `{…}`:
381270

382271
```js run
383-
'use strict';
384-
385-
*!*
386-
let getTime = () => {
387-
let date = new Date();
388-
let hours = date.getHours();
389-
let minutes = date.getMinutes();
390-
return hourse + ':' + minutes;
391-
};
392-
*/!*
272+
let arr = [5, 7, -8, 1];
393273

394-
alert( getTime() ); // текущее время
274+
alert( Math.max(...arr) ); // 7
395275
```
396276

397-
Заметим, что как только тело функции оборачивается в `{…}`, то её результат уже не возвращается автоматически. Такая функция должна делать явный `return`, как в примере выше, если конечно хочет что-либо возвратить.
277+
In short:
278+
- When `...` occurs in function parameters, it's called a "rest operator" and gathers parameters into the array.
279+
- When `...` occurs in a function call, it's called a "spread operator" and unfurls an array into the list.
398280

399-
Функции-стрелки очень удобны в качестве коллбеков, например:
400-
401-
```js run
402-
`use strict`;
281+
Together they help to travel between a list and an array of parameters with ease.
403282

404-
let arr = [5, 8, 3];
405-
406-
*!*
407-
let sorted = arr.sort( (a,b) => a - b );
408-
*/!*
409-
410-
alert(sorted); // 3, 5, 8
411-
```
412-
413-
Такая запись -- коротка и понятна. Далее мы познакомимся с дополнительными преимуществами использования функций-стрелок для этой цели.
414-
415-
## Функции-стрелки не имеют своего this
416-
417-
Внутри функций-стрелок -- тот же `this`, что и снаружи.
418-
419-
Это очень удобно в обработчиках событий и коллбэках, например:
420-
421-
```js run
422-
'use strict';
423-
424-
let group = {
425-
title: "Наш курс",
426-
students: ["Вася", "Петя", "Даша"],
427-
428-
showList: function() {
429-
*!*
430-
this.students.forEach(
431-
student => alert(this.title + ': ' + student)
432-
)
433-
*/!*
434-
}
435-
}
436-
437-
group.showList();
438-
// Наш курс: Вася
439-
// Наш курс: Петя
440-
// Наш курс: Даша
441-
```
442-
443-
Здесь в `forEach` была использована функция-стрелка, поэтому `this.title` в коллбэке -- тот же, что и во внешней функции `showList`. То есть, в данном случае -- `group.title`.
444-
445-
Если бы в `forEach` вместо функции-стрелки была обычная функция, то была бы ошибка:
446-
447-
```js run
448-
'use strict';
449-
450-
let group = {
451-
title: "Наш курс",
452-
students: ["Вася", "Петя", "Даша"],
453-
454-
showList: function() {
455-
*!*
456-
this.students.forEach(function(student) {
457-
alert(this.title + ': ' + student); // будет ошибка
458-
})
459-
*/!*
460-
}
461-
}
462-
463-
group.showList();
464-
```
465-
466-
При запуске будет "попытка прочитать свойство `title` у `undefined`", так как `.forEach(f)` при запуске `f` не ставит `this`. То есть, `this` внутри `forEach` будет `undefined`.
467-
468-
```warn header="Функции стрелки нельзя запускать с `new`"
469-
Отсутствие у функции-стрелки "своего `this`" влечёт за собой естественное ограничение: такие функции нельзя использовать в качестве конструктора, то есть нельзя вызывать через `new`.
470-
```
471-
472-
```smart header="=> это не то же самое, что `.bind(this)`"
473-
Есть тонкое различие между функцией стрелкой `=>` и обычной функцией, у которой вызван `.bind(this)`:
474-
475-
- Вызовом `.bind(this)` мы передаём текущий `this`, привязывая его к функции.
476-
- При `=>` привязки не происходит, так как функция стрелка вообще не имеет контекста `this`. Поиск `this` в ней осуществляется так же, как и поиск обычной переменной, то есть, выше в замыкании. До появления стандарта ES-2015 такое было невозможно.
477-
```
478-
479-
## Функции-стрелки не имеют своего arguments
480-
481-
В качестве `arguments` используются аргументы внешней "обычной" функции.
482-
483-
Например:
484-
485-
```js run
486-
'use strict';
487-
488-
function f() {
489-
let showArg = () => alert(arguments[0]);
490-
showArg();
491-
}
492-
493-
f(1); // 1
494-
```
495-
496-
Вызов `showArg()` выведет `1`, получив его из аргументов функции `f`. Функция-стрелка здесь вызвана без параметров, но это не важно: `arguments` всегда берутся из внешней "обычной" функции.
497-
498-
Сохранение внешнего `this` и `arguments` удобно использовать для форвардинга вызовов и создания декораторов.
499-
500-
Например, декоратор `defer(f, ms)` ниже получает функцию `f` и возвращает обёртку вокруг неё, откладывающую вызов на `ms` миллисекунд:
501-
502-
```js run
503-
'use strict';
504-
505-
*!*
506-
function defer(f, ms) {
507-
return function() {
508-
setTimeout(() => f.apply(this, arguments), ms)
509-
}
510-
}
511-
*/!*
512-
513-
function sayHi(who) {
514-
alert('Привет, ' + who);
515-
}
516-
517-
let sayHiDeferred = defer(sayHi, 2000);
518-
sayHiDeferred("Вася"); // Привет, Вася через 2 секунды
519-
```
520-
521-
Аналогичная реализация без функции-стрелки выглядела бы так:
522-
523-
```js
524-
function defer(f, ms) {
525-
return function() {
526-
*!*
527-
let args = arguments;
528-
let ctx = this;
529-
*/!*
530-
setTimeout(function() {
531-
return f.apply(ctx, args);
532-
}, ms);
533-
}
534-
}
535-
```
536283

537-
В этом коде пришлось создавать дополнительные переменные `args` и `ctx` для передачи внешних аргументов и контекста через замыкание.
538284

539285
## Итого
540286

0 commit comments

Comments
 (0)