update func
This commit is contained in:
@@ -46,4 +46,50 @@ message = 'Hello';
|
||||
```js
|
||||
typeof null == "object" // ошибка в языке
|
||||
typeof function(){} == "function" // именно для функций
|
||||
```
|
||||
|
||||
## Устаревшее ключевое слово "var"
|
||||
Обычно var не используется в современных скриптах, но всё ещё может скрываться в старых.\
|
||||
|
||||
Существует 2 основных отличия var от let/const:
|
||||
- Переменные var не имеют блочной области видимости, они ограничены, как минимум, телом функции.
|
||||
- Объявления (инициализация) переменных var производится в начале исполнения функции (или скрипта для глобальных переменных).
|
||||
|
||||
### Для «var» не существует блочной области видимости
|
||||
Область видимости переменных `var` ограничивается либо функцией, либо, если переменная глобальная, то скриптом. Такие переменные доступны за пределами блока.
|
||||
|
||||
`var` выходит за пределы блоков `if`, `for` и подобных. Это происходит потому, что на заре развития JavaScript блоки кода не имели лексического окружения.
|
||||
|
||||
### «var» допускает повторное объявление
|
||||
Используя var, можно переобъявлять переменную сколько угодно раз. Повторные var игнорируются.
|
||||
|
||||
### «var» обрабатываются в начале запуска функции
|
||||
Это поведение называется «hoisting» (всплытие, поднятие), потому что все объявления переменных var «всплывают» в самый верх функции.
|
||||
Объявления переменных var обрабатываются в начале выполнения функции (или запуска скрипта, если переменная является глобальной).
|
||||
|
||||
Другими словами, переменные var считаются объявленными с самого начала исполнения функции вне зависимости от того, в каком месте функции реально находятся их объявления (при условии, что они не находятся во вложенной функции).
|
||||
|
||||
***Объявления переменных «всплывают», но присваивания значений – нет.***
|
||||
|
||||
### IIFE
|
||||
В прошлом, поскольку существовал только `var`, а он не имел блочной области видимости, программисты придумали способ её эмулировать. Этот способ получил название «Immediately-invoked function expressions» (сокращенно IIFE).
|
||||
Здесь создаётся и немедленно вызывается Function Expression. Так что код выполняется сразу же и у него есть свои локальные переменные.
|
||||
```js
|
||||
// Способы создания IIFE
|
||||
(function() {
|
||||
var message = "Привет";
|
||||
alert(message); // Привет
|
||||
})(); // Круглые скобки вокруг функции
|
||||
|
||||
(function() {
|
||||
alert("Круглые скобки вокруг всего выражения");
|
||||
}());
|
||||
|
||||
!function() {
|
||||
alert("Выражение начинается с логического оператора НЕ");
|
||||
}();
|
||||
|
||||
+function() {
|
||||
alert("Выражение начинается с унарного плюса");
|
||||
}();
|
||||
```
|
||||
77
docs/javascript/02-objects/08-getter-setter.md
Normal file
77
docs/javascript/02-objects/08-getter-setter.md
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# Свойства - геттеры и сеттеры
|
||||
|
||||
## Геттеры и сеттеры
|
||||
Свойства-аксессоры представлены методами: «геттер» – для чтения и «сеттер» – для записи. При литеральном объявлении объекта они обозначаются get и set
|
||||
```js
|
||||
let obj = {
|
||||
get propName() {
|
||||
// геттер, срабатывает при чтении obj.propName
|
||||
},
|
||||
|
||||
set propName(value) {
|
||||
// сеттер, срабатывает при записи obj.propName = value
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Дескрипторы свойств доступа
|
||||
Дескрипторы свойств-аксессоров отличаются от «обычных» свойств-данных.
|
||||
|
||||
Свойства-аксессоры не имеют `value` и `writable`, но взамен предлагают функции `get` и `set`.
|
||||
|
||||
То есть, дескриптор аксессора может иметь:
|
||||
- **get** – функция без аргументов, которая сработает при чтении свойства,
|
||||
- **set** – функция, принимающая один аргумент, вызываемая при присвоении свойства,
|
||||
- **enumerable** – то же самое, что и для свойств-данных,
|
||||
- **configurable** – то же самое, что и для свойств-данных.
|
||||
|
||||
Например, для создания аксессора `fullName` при помощи `defineProperty` мы можем передать дескриптор с использованием `get` и `set`
|
||||
```js
|
||||
let user = {
|
||||
name: "John",
|
||||
surname: "Smith"
|
||||
};
|
||||
|
||||
Object.defineProperty(user, 'fullName', {
|
||||
get() {
|
||||
return `${this.name} ${this.surname}`;
|
||||
},
|
||||
set(value) {
|
||||
[this.name, this.surname] = value.split(" ");
|
||||
}
|
||||
});
|
||||
alert(user.fullName); // John Smith
|
||||
for(let key in user) alert(key); // name, surname
|
||||
```
|
||||
|
||||
## Умные геттеры/сеттеры
|
||||
Геттеры/сеттеры можно использовать как обёртки над «реальными» значениями свойств, чтобы получить больше контроля над операциями с ними.
|
||||
|
||||
Например, если мы хотим запретить устанавливать короткое имя для `user`, мы можем использовать сеттер `name` для проверки, а само значение хранить в отдельном свойстве `_name`:
|
||||
```js
|
||||
let user = {
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
set name(value) {
|
||||
if (value.length < 4) {
|
||||
alert("Имя слишком короткое, должно быть более 4 символов");
|
||||
return;
|
||||
}
|
||||
this._name = value;
|
||||
}
|
||||
};
|
||||
|
||||
user.name = "Pete";
|
||||
alert(user.name); // Pete
|
||||
|
||||
user.name = ""; // Имя слишком короткое...
|
||||
```
|
||||
|
||||
## Использование для совместимости
|
||||
У аксессоров есть интересная область применения – они позволяют в любой момент взять «обычное» свойство и изменить его поведение, поменяв на геттер и сеттер.
|
||||
62
docs/javascript/03-data-types/11-json.md
Normal file
62
docs/javascript/03-data-types/11-json.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
sidebar_position: 11
|
||||
---
|
||||
|
||||
# Формат JSON
|
||||
|
||||
- JSON – это формат данных, который имеет собственный независимый стандарт и библиотеки для большинства языков программирования.
|
||||
- JSON поддерживает простые объекты, массивы, строки, числа, логические значения и null.
|
||||
- JavaScript предоставляет методы JSON.stringify для сериализации в JSON и JSON.parse для чтения из JSON.
|
||||
- Оба метода поддерживают функции преобразования для интеллектуального чтения/записи.
|
||||
- Если объект имеет метод toJSON, то он вызывается через JSON.stringify.
|
||||
|
||||
JavaScript предоставляет методы:
|
||||
|
||||
- JSON.stringify для преобразования объектов в JSON.
|
||||
- JSON.parse для преобразования JSON обратно в объект.
|
||||
|
||||
JSON поддерживает следующие типы данных:
|
||||
|
||||
- Объекты \{ ... }
|
||||
- Массивы [ ... ]
|
||||
- Примитивы:
|
||||
- строки,
|
||||
- числа,
|
||||
- логические значения true/false,
|
||||
- null.
|
||||
|
||||
## JSON.stringify
|
||||
JSON.stringify пропускает некоторые специфические свойства объектов JavaScript
|
||||
- Свойства-функции (методы).
|
||||
- Символьные ключи и значения.
|
||||
- Свойства, содержащие undefined.
|
||||
|
||||
💥 ***Важное ограничение: не должно быть циклических ссылок.***
|
||||
|
||||
## Исключаем и преобразуем: replacer
|
||||
- **value** Значение для кодирования.
|
||||
- **replacer** Массив свойств для кодирования или функция соответствия function(key, value).
|
||||
- **space** Дополнительное пространство (отступы), используемое для форматирования.
|
||||
|
||||
В большинстве случаев JSON.stringify используется только с первым аргументом. Но если нам нужно настроить процесс замены, например, отфильтровать циклические ссылки, то можно использовать второй аргумент JSON.stringify.
|
||||
|
||||
```js
|
||||
let json = JSON.stringify(value[, replacer, space])
|
||||
```
|
||||
|
||||
## Форматирование: space
|
||||
Третий аргумент в JSON.stringify(value, replacer, space) – это количество пробелов, используемых для удобного форматирования.
|
||||
|
||||
## Пользовательский «toJSON»
|
||||
Как и toString для преобразования строк, объект может предоставлять метод toJSON для преобразования в JSON. JSON.stringify автоматически вызывает его, если он есть.
|
||||
|
||||
## JSON.parse
|
||||
Чтобы декодировать JSON-строку, нам нужен другой метод с именем JSON.parse.
|
||||
```js
|
||||
let value = JSON.parse(str[, reviver]);
|
||||
```
|
||||
- **str** JSON для преобразования в объект.
|
||||
- **reviver** Необязательная функция, которая будет вызываться для каждой пары (ключ, значение) и может преобразовывать значение.
|
||||
|
||||
Кроме того, JSON не поддерживает комментарии.
|
||||
|
||||
@@ -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