update func
This commit is contained in:
@@ -47,3 +47,49 @@ message = 'Hello';
|
|||||||
typeof null == "object" // ошибка в языке
|
typeof null == "object" // ошибка в языке
|
||||||
typeof function(){} == "function" // именно для функций
|
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.
|
- Не имеют this.
|
||||||
- Не имеют arguments.
|
- Не имеют arguments.
|
||||||
- Не могут быть вызваны с new.
|
- Не могут быть вызваны с 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