update func
This commit is contained in:
@@ -53,7 +53,7 @@ function defer(f, ms) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Стрелочные функции:
|
||||
## Особенности стрелочных функций:
|
||||
- Не имеют this.
|
||||
- Не имеют arguments.
|
||||
- Не могут быть вызваны с new.
|
||||
|
||||
62
docs/javascript/04-functions/05-args.md
Normal file
62
docs/javascript/04-functions/05-args.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Остаточные параметры и оператор расширения
|
||||
|
||||
Когда мы видим "..." в коде, это могут быть как остаточные параметры, так и оператор расширения.
|
||||
|
||||
Как отличить их друг от друга:
|
||||
|
||||
- Если ... располагается в конце списка параметров функции, то это «остаточные параметры». Он собирает остальные неуказанные аргументы и делает из них массив.
|
||||
- Если ... встретился в вызове функции или где-либо ещё, то это «оператор расширения». Он извлекает элементы из массива.
|
||||
|
||||
Полезно запомнить:
|
||||
- Остаточные параметры используются, чтобы создавать новые функции с неопределённым числом аргументов.
|
||||
- С помощью оператора расширения можно вставить массив в функцию, которая по умолчанию работает с обычным списком аргументов.
|
||||
-
|
||||
Вместе эти конструкции помогают легко преобразовывать наборы значений в массивы и обратно.
|
||||
|
||||
К аргументам функции можно обращаться и по-старому — через псевдомассив arguments.
|
||||
|
||||
## Остаточные параметры (...)
|
||||
Остаточные параметры могут быть обозначены через три точки `....`
|
||||
```js
|
||||
function sumAll(...args) { // args — имя массива
|
||||
let sum = 0;
|
||||
for (let arg of args) sum += arg;
|
||||
return sum;
|
||||
}
|
||||
alert( sumAll(1) ); // 1
|
||||
alert( sumAll(1, 2) ); // 3
|
||||
alert( sumAll(1, 2, 3) ); // 6
|
||||
```
|
||||
💥 ***Остаточные параметры должны располагаться в конце***
|
||||
```js
|
||||
function f(arg1, ...rest, arg2) { // arg2 после ...rest ?!
|
||||
// Ошибка
|
||||
}
|
||||
```
|
||||
## Переменная "arguments"
|
||||
Все аргументы функции находятся в псевдомассиве `arguments` под своими порядковыми номерами.
|
||||
Хотя arguments похож на массив, и его тоже можно перебирать, это всё же не массив. Методы массивов не поддерживаются.
|
||||
```js
|
||||
function showName() {
|
||||
alert( arguments.length );
|
||||
alert( arguments[0] );
|
||||
alert( arguments[1] );
|
||||
// for (let arg of arguments) alert(arg); // Объект arguments можно перебирать
|
||||
}
|
||||
showName("Юлий", "Цезарь"); // Вывод: 2, Юлий, Цезарь
|
||||
showName("Илья");// Вывод: 1, Илья, undefined (второго аргумента нет)
|
||||
```
|
||||
💥 ***Стрелочные функции не имеют "arguments"***
|
||||
Если мы обратимся к arguments из стрелочной функции, то получим аргументы внешней «нормальной» функции.
|
||||
|
||||
## Оператор расширения
|
||||
Когда `...arr` используется при вызове функции, он «расширяет» перебираемый объект `arr` в список аргументов.
|
||||
```js
|
||||
let arr = [3, 5, 1];
|
||||
alert( Math.max(...arr) ); // 5 (оператор "раскрывает" массив в список аргументов)
|
||||
```
|
||||
|
||||
113
docs/javascript/04-functions/06-closure.md
Normal file
113
docs/javascript/04-functions/06-closure.md
Normal file
@@ -0,0 +1,113 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Область видимости переменных, замыкание
|
||||
Источник: [https://learn.javascript.ru/closure](https://learn.javascript.ru/closure)
|
||||
|
||||
## Блоки кода
|
||||
Если переменная объявлена внутри блока кода `{...}`, то она видна только внутри этого блока.
|
||||
С помощью блоков `{...}` мы можем изолировать часть кода, выполняющую свою собственную задачу, с переменными, принадлежащими только ей
|
||||
Для `if`, `for`, `while` и т.д. переменные, объявленные в блоке кода `{...}`, также видны только внутри
|
||||
|
||||
## Вложенные функции
|
||||
Функция называется «вложенной», когда она создаётся внутри другой функции.
|
||||
Она может получить доступ к внешним переменным.
|
||||
Вложенная функция может быть возвращена: либо в качестве свойства нового объекта (если внешняя функция создаёт объект с методами), либо сама по себе. И затем может быть использована в любом месте. Не важно где, она всё так же будет иметь доступ к тем же внешним переменным.
|
||||
|
||||
## Лексическое окружение
|
||||
|
||||
#### Переменные
|
||||
В JavaScript у каждой выполняемой функции, блока кода `{...}` и скрипта есть связанный с ними внутренний (скрытый) объект, называемый ***лексическим окружением** `LexicalEnvironment`.
|
||||
|
||||
Объект лексического окружения состоит из двух частей:
|
||||
1. **Environment Record** – объект, в котором как свойства хранятся все локальные переменные (а также некоторая другая информация, такая как значение this).
|
||||
2. Ссылка на **внешнее лексическое окружение** – то есть то, которое соответствует коду снаружи (снаружи от текущих фигурных скобок).
|
||||
|
||||
**«Переменная» – это просто свойство специального внутреннего объекта: `Environment Record`.** \
|
||||
**«Получить или изменить переменную», означает, «получить или изменить свойство этого объекта».**
|
||||
|
||||
- Переменная – это свойство специального внутреннего объекта, связанного с текущим выполняющимся блоком/функцией/скриптом.
|
||||
- Работа с переменными – это на самом деле работа со свойствами этого объекта.
|
||||
|
||||
#### Function Declaration
|
||||
**Разница заключается в том, что Function Declaration мгновенно инициализируется полностью.**
|
||||
|
||||
Когда создается лексическое окружение, Function Declaration сразу же становится функцией, готовой к использованию (в отличие от `let`, который до момента объявления не может быть использован).
|
||||
|
||||
Поэтому мы можем вызвать функцию, объявленную как Function Declaration, до самого её объявления.
|
||||
|
||||
Такое поведение касается только Function Declaration, а не Function Expression, в которых мы присваиваем функцию переменной.
|
||||
|
||||
#### Внутреннее и внешнее лексическое окружение
|
||||
Когда запускается функция, в начале ее вызова автоматически создается новое лексическое окружение для хранения локальных переменных и параметров вызова.
|
||||
|
||||

|
||||
|
||||
В процессе вызова функции у нас есть два лексических окружения: внутреннее (для вызываемой функции) и внешнее (глобальное):
|
||||
|
||||
- Внутреннее лексическое окружение соответствует текущему выполнению say.\
|
||||
В нём находится одна переменная name, параметр функции. Мы вызываем say("John"), так что значение переменной name равно "John".
|
||||
- Внешнее лексическое окружение – это глобальное лексическое окружение.\
|
||||
В нём находятся переменная phrase и сама функция.
|
||||
|
||||
У внутреннего лексического окружения есть ссылка на внешнее `outer`.
|
||||
|
||||
**Когда код хочет получить доступ к переменной – сначала происходит поиск во внутреннем лексическом окружении, затем во внешнем, затем в следующем и так далее, до глобального.**
|
||||
|
||||
Если переменная не была найдена, это будет ошибкой в строгом режиме (`use strict`). Без строгого режима, для обратной совместимости, присваивание несуществующей переменной создаёт новую глобальную переменную с таким же именем.
|
||||
|
||||
#### Возврат функции
|
||||
```js
|
||||
function makeCounter() {
|
||||
let count = 0;
|
||||
|
||||
return function() {
|
||||
return count++;
|
||||
};
|
||||
}
|
||||
|
||||
let counter = makeCounter();
|
||||
```
|
||||
В начале каждого вызова makeCounter() создается новый объект лексического окружения, в котором хранятся переменные для конкретного запуска makeCounter.
|
||||
|
||||
Таким образом, мы имеем два вложенных лексических окружения, как в примере выше:
|
||||

|
||||
Отличие заключается в том, что во время выполнения makeCounter() создается крошечная вложенная функция, состоящая всего из одной строки: return count++. Мы ее еще не запускаем, а только создаем.
|
||||
|
||||
Все функции помнят лексическое окружение, в котором они были созданы. Технически здесь нет никакой магии: все функции имеют скрытое свойство [[Environment]], которое хранит ссылку на лексическое окружение, в котором была создана функция:
|
||||

|
||||
|
||||
Таким образом, counter.[[Environment]] имеет ссылку на \{count: 0} лексического окружения. Так функция запоминает, где она была создана, независимо от того, где она вызывается. Ссылка на [[Environment]] устанавливается один раз и навсегда при создании функции.
|
||||
|
||||
Впоследствии, при вызове counter(), для этого вызова создается новое лексическое окружение, а его внешняя ссылка на лексическое окружение берется из counter.[[Environment]]:
|
||||

|
||||
Теперь, когда код внутри counter() ищет переменную count, он сначала ищет ее в собственном лексическом окружении (пустом, так как там нет локальных переменных), а затем в лексическом окружении внешнего вызова makeCounter(), где находит count и изменяет ее.
|
||||
|
||||
***Переменная обновляется в том лексическом окружении, в котором она существует.***
|
||||

|
||||
Если мы вызовем counter() несколько раз, то в одном и том же месте переменная count будет увеличена до 2, 3 и т.д.
|
||||
|
||||
💥 **Замыкания**
|
||||
|
||||
**Замыкание** – это функция, которая запоминает свои внешние переменные и может получить к ним доступ. В некоторых языках это невозможно, или функция должна быть написана специальным образом, чтобы получилось замыкание. Но, как было описано выше, в JavaScript, все функции изначально являются замыканиями.
|
||||
|
||||
То есть они автоматически запоминают, где были созданы, с помощью скрытого свойства `[[Environment]]`, и все они могут получить доступ к внешним переменным.
|
||||
|
||||
Когда на собеседовании фронтенд-разработчику задают вопрос: «что такое замыкание?», – правильным ответом будет определение замыкания и объяснения того факта, что все функции в JavaScript являются замыканиями, и, может быть, несколько слов о технических деталях: свойстве `[[Environment]]` и о том, как работает лексическое окружение.
|
||||
|
||||
Есть только одно исключение, когда функция создаётся с использованием `new Function`, в её `[[Environment]]` записывается ссылка не на внешнее лексическое окружение, в котором она была создана, а на глобальное. Поэтому такая функция имеет доступ только к глобальным переменным.
|
||||
|
||||
## Сборка мусора
|
||||
Обычно лексическое окружение удаляется из памяти вместе со всеми переменными после завершения вызова функции. Это связано с тем, что на него нет ссылок. Как и любой объект JavaScript, оно хранится в памяти только до тех пор, пока к нему можно обратиться.
|
||||
|
||||
Однако если существует вложенная функция, которая все еще доступна после завершения функции, то она имеет свойство `[[Environment]]`, ссылающееся на лексическое окружение.
|
||||
|
||||
В этом случае лексическое окружение остается доступным даже после завершения работы функции.
|
||||
|
||||
Объект лексического окружения исчезает, когда становится недоступным (как и любой другой объект). Другими словами, он существует только до тех пор, пока на него ссылается хотя бы одна вложенная функция.
|
||||
|
||||
#### Оптимизация на практике
|
||||
Но на практике движки JavaScript пытаются это оптимизировать. Они анализируют использование переменных и, если легко по коду понять, что внешняя переменная не используется – она удаляется.
|
||||
|
||||
***Одним из важных побочных эффектов в V8 (Chrome, Edge, Opera) является то, что такая переменная становится недоступной при отладке.***
|
||||
20
docs/javascript/04-functions/07-global-object.md
Normal file
20
docs/javascript/04-functions/07-global-object.md
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Глобальный объект
|
||||
Глобальный объект предоставляет переменные и функции, доступные в любом месте программы. По умолчанию это те, что встроены в язык или среду исполнения.
|
||||
|
||||
В браузере он называется `window`, в Node.js — `global`, в другой среде исполнения может называться иначе.
|
||||
|
||||
Недавно `globalThis` был добавлен в язык как стандартизированное имя для глобального объекта, которое должно поддерживаться в любом окружении.
|
||||
|
||||
В браузере глобальные функции и переменные, объявленные с помощью `var` (не `let/const`!), становятся свойствами глобального объекта:
|
||||
|
||||
- Глобальный объект хранит переменные, которые должны быть доступны в любом месте программы.
|
||||
- Это включает в себя как встроенные объекты, например, Array, так и характерные для окружения свойства, например, window.innerHeight – высота окна браузера.
|
||||
- Глобальный объект имеет универсальное имя – globalThis.
|
||||
- …Но чаще на него ссылаются по-старому, используя имя, характерное для данного окружения, такое как window (браузер) и global (Node.js).
|
||||
- Следует хранить значения в глобальном объекте, только если они действительно глобальны для нашего проекта. И стараться свести их количество к минимуму.
|
||||
- В браузерах, если только мы не используем модули, глобальные функции и переменные, объявленные с помощью var, становятся свойствами глобального объекта.
|
||||
- Для того, чтобы код был проще и в будущем его легче было поддерживать, следует обращаться к свойствам глобального объекта напрямую, как window.x.
|
||||
69
docs/javascript/04-functions/08-setTimeout-setInterval.md
Normal file
69
docs/javascript/04-functions/08-setTimeout-setInterval.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# Планирование: setTimeout и setInterval
|
||||
- Методы `setInterval(func, delay, ...args)` и `setTimeout(func, delay, ...args)` позволяют выполнять func регулярно или только один раз после задержки `delay`, заданной в мс.
|
||||
- Для отмены выполнения необходимо вызвать `clearInterval/clearTimeout` со значением, которое возвращают методы `setInterval/setTimeout`.
|
||||
- Вложенный вызов `setTimeout` является более гибкой альтернативой `setInterval`. Также он позволяет более точно задать интервал между выполнениями.
|
||||
- Планирование с нулевой задержкой `setTimeout(func,0)` или, что то же самое, `setTimeout(func)` используется для вызовов, которые должны быть исполнены как можно скорее, после завершения исполнения текущего кода.
|
||||
- Браузер ограничивает 4-мя мс минимальную задержку между пятью и более вложенными вызовами `setTimeout`, а также для `setInterval`, начиная с 5-го вызова.
|
||||
|
||||
Методы планирования не гарантируют точную задержку. Например, таймер в браузере может замедляться по многим причинам:
|
||||
- Перегружен процессор.
|
||||
- Вкладка браузера в фоновом режиме.
|
||||
- Работа ноутбука от аккумулятора.
|
||||
|
||||
Всё это может увеличивать минимальный интервал срабатывания таймера (и минимальную задержку) до 300 или даже 1000 мс в зависимости от браузера и настроек производительности ОС.
|
||||
|
||||
## setTimeout
|
||||
setTimeout позволяет вызвать функцию один раз через определённый интервал времени.
|
||||
|
||||
```js
|
||||
let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...);
|
||||
```
|
||||
💥 Передавайте функцию, но не запускайте её
|
||||
Разработчики иногда ошибаются, добавляя скобки () после функции. Это не работает, потому что `setTimeout` ожидает ссылку на функцию.
|
||||
|
||||
Вызов `setTimeout` возвращает «идентификатор таймера» `timerId`, который можно использовать для отмены дальнейшего выполнения.
|
||||
```js
|
||||
let timerId = setTimeout(...);
|
||||
clearTimeout(timerId);
|
||||
```
|
||||
## setInterval
|
||||
`setInterval` позволяет вызывать функцию регулярно, повторяя вызов через определённый интервал времени.
|
||||
Метод `setInterval` имеет такой же синтаксис как `setTimeout`
|
||||
|
||||
```js
|
||||
let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...);
|
||||
```
|
||||
Чтобы остановить дальнейшее выполнение функции, необходимо вызвать clearInterval(timerId).
|
||||
|
||||
## Вложенный setTimeout
|
||||
Есть два способа запускать что-то регулярно. Один из них `setInterval`. Другим является вложенный `setTimeout`.
|
||||
|
||||
Вложенный `setTimeout` – более гибкий метод, чем `setInterval`. С его помощью последующий вызов может быть задан по-разному в зависимости от результатов предыдущего.
|
||||
|
||||
Например, необходимо написать сервис, который отправляет запрос для получения данных на сервер каждые 5 секунд, но если сервер перегружен, то необходимо увеличить интервал запросов до 10, 20, 40 секунд… Вот псевдокод:
|
||||
```js
|
||||
let delay = 5000;
|
||||
|
||||
let timerId = setTimeout(function request() {
|
||||
...отправить запрос...
|
||||
|
||||
if (ошибка запроса из-за перегрузки сервера) {
|
||||
// увеличить интервал для следующего запроса
|
||||
delay *= 2;
|
||||
}
|
||||
|
||||
timerId = setTimeout(request, delay);
|
||||
|
||||
}, delay);
|
||||
```
|
||||
***Вложенный `setTimeout` позволяет задать задержку между выполнениями более точно, чем `setInterval`.***
|
||||
|
||||
## setTimeout с нулевой задержкой
|
||||
Особый вариант использования: `setTimeout(func, 0)` или просто `setTimeout(func)`.
|
||||
Это планирует вызов `func` настолько быстро, насколько это возможно. Но планировщик будет вызывать функцию только после завершения выполнения текущего кода.
|
||||
|
||||
Так вызов функции будет запланирован сразу после выполнения текущего кода.
|
||||
25
docs/javascript/04-functions/09-decorators-call-apply.md
Normal file
25
docs/javascript/04-functions/09-decorators-call-apply.md
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
# Декораторы и переадресация вызова, call/apply
|
||||
Источник [https://learn.javascript.ru/call-apply-decorators](https://learn.javascript.ru/call-apply-decorators)
|
||||
|
||||
Декоратор – это обёртка вокруг функции, которая изменяет поведение последней. Основная работа по-прежнему выполняется функцией.
|
||||
|
||||
Обычно безопасно заменить функцию или метод декорированным, за исключением одной мелочи. Если исходная функция предоставляет свойства, такие как `func.calledCount` или типа того, то декорированная функция их не предоставит. Потому что это обёртка. Так что нужно быть осторожным в их использовании. Некоторые декораторы предоставляют свои собственные свойства.
|
||||
|
||||
Декораторы можно рассматривать как «дополнительные возможности» или «аспекты», которые можно добавить в функцию. Мы можем добавить один или несколько декораторов. И всё это без изменения кода оригинальной функции!
|
||||
|
||||
Для реализации `cachingDecorator` мы используем методы:
|
||||
- `func.call(context, arg1, arg2…)` – вызывает `func` с данным контекстом и аргументами.
|
||||
- `func.apply(context, args)` – вызывает `func`, передавая `context` как `this` и псевдомассив `args` как список аргументов.
|
||||
|
||||
В основном переадресация вызова выполняется с помощью apply:
|
||||
```js
|
||||
let wrapper = function(original, arguments) {
|
||||
return original.apply(this, arguments);
|
||||
};
|
||||
```
|
||||
Весьма распространено заимствовать методы массива и применять их к arguments. В качестве альтернативы можно использовать объект с остаточными параметрами ...args, который является реальным массивом.
|
||||
|
||||
64
docs/javascript/04-functions/10-apply-context.md
Normal file
64
docs/javascript/04-functions/10-apply-context.md
Normal file
@@ -0,0 +1,64 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# Привязка контекста к функции
|
||||
Источник: [https://learn.javascript.ru/bind](https://learn.javascript.ru/bind)
|
||||
|
||||
При передаче методов объекта в качестве колбэков, например для setTimeout, возникает известная проблема – потеря this.
|
||||
|
||||
Метод `bind` возвращает «привязанный вариант» функции `func`, фиксируя контекст `this` и первые аргументы `arg1`, `arg2…`, если они заданы.
|
||||
|
||||
Обычно `bind` применяется для фиксации `this` в методе объекта, чтобы передать его в качестве колбэка. Например, для `setTimeout`.
|
||||
|
||||
Когда мы привязываем аргументы, такая функция называется «частично применённой» или «частичной».
|
||||
|
||||
Частичное применение удобно, когда мы не хотим повторять один и тот же аргумент много раз. Например, если у нас есть функция send(from, to) и from всё время будет одинаков для нашей задачи, то мы можем создать частично применённую функцию и дальше работать с ней.
|
||||
|
||||
## Потеря «this»
|
||||
Мы уже видели примеры потери `this`. Как только метод передаётся отдельно от объекта – `this` теряется.
|
||||
|
||||
```js
|
||||
let user = {
|
||||
firstName: "Вася",
|
||||
sayHi() {
|
||||
alert(`Привет, ${this.firstName}!`);
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(user.sayHi, 1000); // Привет, undefined!
|
||||
```
|
||||
Это произошло потому, что setTimeout получил функцию sayHi отдельно от объекта user (именно здесь функция и потеряла контекст).
|
||||
|
||||
> Метод setTimeout в браузере имеет особенность: он устанавливает this=window для вызова функции (в Node.js this становится объектом таймера, но здесь это не имеет значения). Таким образом, для this.firstName он пытается получить window.firstName, которого не существует. В других подобных случаях this обычно просто становится undefined.
|
||||
|
||||
## Решение 1: сделать функцию-обёртку
|
||||
Самый простой вариант решения – это обернуть вызов в анонимную функцию, создав замыкание:
|
||||
```js
|
||||
let user = {
|
||||
firstName: "Вася",
|
||||
sayHi() {
|
||||
alert(`Привет, ${this.firstName}!`);
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(function() {
|
||||
user.sayHi(); // Привет, Вася!
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
## Решение 2: привязать контекст с помощью bind
|
||||
Результатом вызова `func.bind(context)` является особый «экзотический объект» (термин взят из спецификации), который вызывается как функция и прозрачно передаёт вызов в `func`, при этом устанавливая `this=context`.
|
||||
|
||||
Другими словами, вызов boundFunc подобен вызову `func` с фиксированным `this`.
|
||||
```js
|
||||
let user = {
|
||||
firstName: "Вася",
|
||||
sayHi() {
|
||||
alert(`Привет, ${this.firstName}!`);
|
||||
}
|
||||
};
|
||||
let sayHi = user.sayHi.bind(user); // (*)
|
||||
sayHi(); // Привет, Вася!
|
||||
setTimeout(sayHi, 1000); // Привет, Вася!
|
||||
```
|
||||
BIN
docs/javascript/04-functions/images/06-closure-1.png
Normal file
BIN
docs/javascript/04-functions/images/06-closure-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/javascript/04-functions/images/06-closure-2.png
Normal file
BIN
docs/javascript/04-functions/images/06-closure-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/javascript/04-functions/images/06-closure-3.png
Normal file
BIN
docs/javascript/04-functions/images/06-closure-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/javascript/04-functions/images/06-closure-4.png
Normal file
BIN
docs/javascript/04-functions/images/06-closure-4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/javascript/04-functions/images/06-closure-5.png
Normal file
BIN
docs/javascript/04-functions/images/06-closure-5.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user