update data types

This commit is contained in:
2025-03-04 16:47:30 +03:00
parent cb53cdf7e0
commit e60ec041ae
10 changed files with 863 additions and 1 deletions

View File

@@ -8,10 +8,21 @@ sidebar_position: 1
#### Примитив
- Это значение «примитивного» типа.
- Есть 7 примитивных типов: string, number, boolean, symbol, null, undefined и bigint.
- Есть 7 примитивных типов: **`string`**, **`number`**, **`boolean`**, **`symbol`**, **`null`**, **`undefined`** и **`bigint`**.
#### Объект
- Может хранить множество значений как свойства.
- Объявляется при помощи фигурных скобок \{\}, например: \{name: "Рома", age: 30\}. В JavaScript есть и другие виды объектов: например, функции тоже являются объектами.
## Примитив как объект
1. Примитивы остаются примитивами. Одно значение, как и хотелось.
2. Язык позволяет осуществлять доступ к методам и свойствам строк, чисел, булевых значений и символов.
3. Чтобы это работало, при таком доступе создаётся специальный «объект-обёртка», который предоставляет нужную функциональность, а после удаляется.
Каждый примитив имеет свой собственный «объект-обёртку», которые называются: **`String`**, **`Number`**, **`Boolean`**, **`Symbol`** и **`BigInt`**. Таким образом, они имеют разный набор методов.
💥 ***null/undefined не имеют методов*** \
Попытка доступа к свойствам такого значения возвратит ошибку:

View File

@@ -0,0 +1,123 @@
---
sidebar_position: 2
---
# Числа
В современном JavaScript существует два типа чисел:
1. Обычные числа в JavaScript хранятся в 64-битном формате IEEE-754, который также называют «числа с плавающей точкой двойной точности» (double precision floating point numbers).
2. BigInt числа дают возможность работать с целыми числами произвольной длины. Они нужны достаточно редко и используются в случаях, когда необходимо работать со значениями более чем (253-1) или менее чем -(253-1).
### Способы записи числа
```js
let billion = 1000000000;
let billion = 1_000_000_000
let billion = 1e9;
```
```js
let mcs = 0.000001;
let ms = 1e-6; // шесть нулей слева от 1
let a = 0b11111111; // двоичная (бинарная) форма записи числа 255
let b = 0o377; // восьмеричная форма записи числа 255
```
### toString(base)
**base** может варьироваться от 2 до 36 (по умолчанию 10).
```js
alert( (255).toString(16) ); // ff
alert( (255).toString(2) ); // 11111111
alert( 123456..toString(36) ); // 2n9c
```
Две точки в 123456..toString(36) это не опечатка. Если нам надо вызвать метод непосредственно на числе, как toString в примере выше, то нам надо поставить две точки .. после числа.
### Округление
- **Math.floor** \
Округление в меньшую сторону: 3.1 становится 3, а -1.1 — -2.
- **Math.ceil** \
Округление в большую сторону: 3.1 становится 4, а -1.1 — -1.
- **Math.round** \
Округление до ближайшего целого: 3.1 становится 3, 3.6 — 4, а -1.1 — -1.
- **Math.trunc** (не поддерживается в Internet Explorer) \
Производит удаление дробной части без округления: 3.1 становится 3, а -1.1 — -1.
- Метод **toFixed(n)** \
округляет число до n знаков после запятой и возвращает строковое представление результата.\
``` alert( (12.34).toFixed(1) ); // "12.3" ```
### Неточные вычисления
Внутри JavaScript число представлено в виде 64-битного формата IEEE-754. Для хранения числа используется 64 бита: 52 из них используется для хранения цифр, 11 для хранения положения десятичной точки и один бит отведён на хранение знака.
```js
alert( 1e500 ); // Infinity
```
Наиболее часто встречающаяся ошибка при работе с числами в JavaScript это потеря точности.
```js
alert( 0.1 + 0.2 ); // 0.30000000000000004
```
И когда мы суммируем 2 числа, их «неточности» тоже суммируются. Наиболее надёжный способ — это округлить результат используя метод toFixed(n):
```js
alert( +(0.1 + 0.2).toFixed(2) ); // 0.3
```
### Проверка: isFinite и isNaN
- Infinity (и -Infinity) — особенное численное значение, которое ведёт себя в точности как математическая бесконечность ∞.
- NaN представляет ошибку.
**isNaN(value)** преобразует значение в число и проверяет является ли оно NaN:
```js
alert( isNaN(NaN) ); // true
alert( isNaN("str") ); // true
alert( NaN === NaN ); // false
```
**isFinite(value)** преобразует аргумент в число и возвращает true, если оно является обычным числом, т.е. не NaN/Infinity/-Infinity
Иногда isFinite используется для проверки, содержится ли в строке число:
```js
alert( isFinite("15") ); // true
alert( isFinite("str") ); // false, потому что специальное значение: NaN
alert( isFinite(Infinity) ); // false, потому что специальное значение: Infinity
// вернёт true всегда, кроме ситуаций, когда аргумент - Infinity/-Infinity или не число
alert( isFinite(num) );
```
Методы **Number.isNaN** и **Number.isFinite** это более «строгие» версии функций isNaN и isFinite. Они не преобразуют аргумент в число, а наоборот первым делом проверяют, является ли аргумент числом (принадлежит ли он к типу number).
Number.isNaN(value) возвращает true только в том случае, если аргумент принадлежит к типу number и является NaN. Во всех остальных случаях возвращает false.
```js
alert( Number.isNaN(NaN) ); // true
alert( Number.isNaN("str" / 2) ); // true
// Обратите внимание на разный результат:
alert( Number.isNaN("str") ); // false, так как "str" является строкой, а не числом
alert( isNaN("str") ); // true, так как isNaN сначала преобразует строку "str" в число и в результате преобразования получает NaN
```
Number.isFinite(value) возвращает true только в том случае, если аргумент принадлежит к типу number и не является NaN/Infinity/-Infinity. Во всех остальных случаях возвращает false.
```js
alert( Number.isFinite(123) ); // true
alert( Number.isFinite(Infinity) ); // false
alert( Number.isFinite(2 / 0) ); // false
// Обратите внимание на разный результат:
alert( Number.isFinite("123") ); // false, так как "123" является строкой, а не числом
alert( isFinite("123") ); // true, так как isFinite сначала преобразует строку "123" в число 123
```
Не стоит считать Number.isNaN и Number.isFinite более «корректными» версиями функций isNaN и isFinite. Это дополняющие друг-друга инструменты для разных задач.
💥 **Сравнение Object.is**
Существует специальный метод Object.is, который сравнивает значения примерно как ===, но более надёжен в двух особых ситуациях:
Работает с NaN: Object.is(NaN, NaN) === true, здесь он хорош.
Значения 0 и -0 разные: Object.is(0, -0) === false, это редко используется, но технически эти значения разные.
Во всех других случаях Object.is(a, b) идентичен a === b.
Этот способ сравнения часто используется в спецификации JavaScript. Когда внутреннему алгоритму необходимо сравнить 2 значения на предмет точного совпадения, он использует Object.is
### parseInt и parseFloat
Для явного преобразования к числу можно использовать + или Number(). Если строка не является в точности числом, то результат будет NaN, пробелы в начале строки и в конце игнорируются.
Функция parseInt() имеет необязательный второй параметр. Он определяет систему счисления,
```js
alert( parseInt('100px') ); // 100
alert( parseFloat('12.5em') ); // 12.5
alert( +"100px" ); // NaN
alert( parseInt('a123') ); // NaN
```
### Другие математические функции
В JavaScript встроен объект **Math**, который содержит различные математические функции и константы.

View File

@@ -0,0 +1,95 @@
---
sidebar_position: 3
---
# Строки
В JavaScript любые текстовые данные являются строками.
Внутренний формат для строк — всегда UTF-16, вне зависимости от кодировки страницы.
### Кавычки
```js
let single = 'single-quoted';
let double = "double-quoted";
let backticks = `backticks`;
```
### Спецсимволы
| Символ | Описание |
|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| \n | Перевод строки |
| \r | В текстовых файлах Windows для перевода строки используется комбинация символов \r\n, а на других ОС это просто \n. Это так по историческим причинам, ПО под Windows обычно понимает и просто \n. |
| \\', \\", \\` | Кавычки |
| \\\ | Обратный слеш |
| \t | Знак табуляции |
| \b, \f, \v | Backspace, Form Feed и Vertical Tab — оставлены для обратной совместимости, сейчас не используются. |
### Длина строки
💥 **length** — это числовое свойство, а не функция, добавлять скобки не нужно.
### Доступ к символам
```js
let str = `Hello`;
// получаем первый символ
alert( str[0] ); // H
alert( str.at(0) ); // H
// получаем последний символ
alert( str[str.length - 1] ); // o
alert( str.at(-1) ); // o
```
Также можно перебрать строку посимвольно, используя for..of:
### Строки неизменяемы
Можно создать новую строку и записать её в ту же самую переменную вместо старой.
### Поиск подстроки
**str.indexOf** - Он ищет подстроку substr в строке str, начиная с позиции pos, и возвращает позицию, на которой располагается совпадение, либо -1 при отсутствии совпадений.
```js
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0, потому что подстрока 'Widget' найдена в начале
alert( str.indexOf('widget') ); // -1, совпадений нет, поиск чувствителен к регистру
alert( str.indexOf("id") ); // 1, подстрока "id" найдена на позиции 1 (..idget with id)
```
💥 str.lastIndexOf(substr, position) - ищет с конца строки к её началу
**includes** - если нам необходимо проверить, есть ли совпадение, но позиция не нужна.
```js
alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
```
**startsWith, endsWith** - начинается ли, заканчивается ли строка определённой строкой
```js
alert( "Widget".startsWith("Wid") ); // true, "Wid" — начало "Widget"
alert( "Widget".endsWith("get") ); // true, "get" — окончание "Widget"
```
### Получение подстроки
В JavaScript есть 3 метода для получения подстроки: **substring**, **substr** и **slice**
Из двух других вариантов, slice более гибок, он поддерживает отрицательные аргументы, и его короче писать. Так что, в принципе, можно запомнить только его.
```js
str.slice(start [, end]) // возвращает часть строки от start до (не включая) end.
str.substring(start [, end]) // возвращает часть строки между start и end (не включая) end.
str.substr(start [, length]) // - возвращает часть строки от start длины length.
```
### Сравнение строк
строки сравниваются посимвольно в алфавитном порядке.
1. Строчные буквы больше заглавных **'a' > 'Z'**
2. Буквы, имеющие диакритические знаки, идут «не по порядку» **'Österreich' > 'Zealand'**
#### Правильное сравнение
«Правильный» алгоритм сравнения строк сложнее, чем может показаться, так как разные языки используют разные алфавиты.
К счастью, все современные браузеры (для IE10 нужна дополнительная библиотека Intl.JS) поддерживают стандарт ECMA 402, обеспечивающий правильное сравнение строк на разных языках с учётом их правил.
Для этого есть соответствующий метод.
Вызов str.localeCompare(str2) возвращает число, которое показывает, какая строка больше в соответствии с правилами языка:
- Отрицательное число, если str меньше str2.
- Положительное число, если str больше str2.
- 0, если строки равны.

View File

@@ -0,0 +1,78 @@
---
sidebar_position: 4
---
# Массивы
Особая структура данных, которая называется массив(Array) - это упорядоченная коллекция данных.
```js
let arr = new Array();
let arr = [];
```
### Получение последних элементов при помощи «at»
```js
let fruits = ["Apple", "Orange", "Plum"];
// то же самое, что и fruits[fruits.length-1]
alert( fruits.at(-1) ); // Plum
```
Другими словами, arr.at(i):
- это ровно то же самое, что и arr[i], если i >= 0.
- для отрицательных значений i, он отступает от конца массива.
### Методы pop/push, shift/unshift
- **`push`** - Добавляет элемент в конец массива
- **`pop`** - Удаляет последний элемент из массива и возвращает его
- **`shift`** - Удаляет из массива первый элемент и возвращает его
- **`unshift`** - Добавляет элемент в начало массива
Методы **`push`** и **`unshift`** могут добавлять сразу несколько элементов
Методы **`push`**/**`pop`** выполняются быстро, а методы **`shift`**/**`unshift`** медленно.
Чтобы пройтись по элементам массива:
- **for (let i=0\; i\<arr.length\; i++)** работает быстрее всего, совместим со старыми браузерами.
- **for (let item of arr)** современный синтаксис только для значений элементов (к индексам нет доступа).
- **for (let i in arr)** никогда не используйте для массивов!
💥 Не следует использовать цикл **for..in** для массивов.
1. Цикл **for..in** выполняет перебор всех свойств объекта, а не только цифровых.
2. Цикл **for..in** оптимизирован под произвольные объекты, не массивы, и поэтому в 10-100 раз медленнее.
Ещё один интересный факт о свойстве **length** его можно перезаписать.\
Cамый простой способ очистить массив это arr.length = 0;
```js
let arr = [1, 2, 3, 4, 5];
arr.length = 2; // укорачиваем до двух элементов
alert( arr ); // [1, 2]
arr.length = 5; // возвращаем length как было
alert( arr[3] ); // undefined: значения не восстановились
```
### new Array()
```js
let arr = new Array("Яблоко", "Груша", "и тд");
```
Если new Array вызывается с одним аргументом, который представляет собой число, он создаёт массив без элементов, но с заданной длиной.
### Многомерные массивы
Массивы могут содержать элементы, которые тоже являются массивами. Это можно использовать для создания многомерных массивов, например, для хранения матриц
```js
let matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
alert( matrix[1][1] ); // 5, центральный элемент
```
### Не сравнивайте массивы при помощи ==
В JavaScript, в отличие от некоторых других языков программирования, массивы не следует сравнивать при помощи оператора ==.
У этого оператора нет специального подхода к массивам, он работает с ними, как и с любыми другими объектами.
Итак, если мы всё же сравниваем массивы с помощью ==, то они никогда не будут одинаковыми, если только мы не сравним две переменные, которые ссылаются на один и тот же массив
Вместо этого сравните их по элементам в цикле или используя методы итерации.

View File

@@ -0,0 +1,167 @@
---
sidebar_position: 5
---
# Методы массивов
### Добавление/удаление элементов
- **arr.push(...items)** добавляет элементы в конец,
- **arr.pop()** извлекает элемент из конца,
- **arr.shift()** извлекает элемент из начала,
- **arr.unshift(...items)** добавляет элементы в начало.
### splice
Это универсальный «швейцарский нож» для работы с массивами. Умеет всё: добавлять, удалять и заменять элементы.
Синтаксис:
```js
arr.splice(start[, deleteCount, elem1, ..., elemN
])
```
Он изменяет arr начиная с индекса start: удаляет deleteCount элементов и затем вставляет elem1, ..., elemN на их место.
Возвращает массив из удалённых элементов.
💥 Отрицательные индексы разрешены
### slice
Возвращает новый массив, в который копирует все элементы с индекса start до end (не включая end). start и end могут быть
отрицательными, в этом случае отсчёт позиции будет вестись с конца массива.
```js
arr.slice([start], [end])
```
Это похоже на строковый метод str.slice, но вместо подстрок возвращает подмассивы.
### concat
Метод arr.concat создаёт новый массив, в который копирует данные из других массивов и дополнительные значения.
```js
let arr = [1, 2];
// создать массив из: arr и [3,4]
alert(arr.concat([3, 4])); // 1,2,3,4
```
### Перебор: forEach
Метод arr.forEach позволяет запускать функцию для каждого элемента массива.
```js
arr.forEach(function (item, index, array) {
// ... делать что-то с item
});
```
## Поиск в массиве
### indexOf/lastIndexOf и includes
- arr.indexOf(item, from) ищет item начиная с индекса from и возвращает номер индекса, на котором был найден искомый
элемент, в противном случае -1.
- arr.includes(item, from) ищет item начиная с индекса from и возвращает true, если поиск успешен.
💥 Метод includes правильно обрабатывает NaN, в отличие от indexOf
### find и findIndex/findLastIndex
Функция вызывается по очереди для каждого элемента массива:
- **item** очередной элемент.
- **index** его индекс.
- **array** сам массив.
Если функция возвращает **true**, поиск прерывается и возвращается **item**. Если ничего не найдено, возвращается
`undefined`.
```js
let result = arr.find(function (item, index, array) {
// если true - возвращается текущий элемент и перебор прерывается
// если все итерации оказались ложными, возвращается undefined
});
```
У метода **arr.findIndex** такой же синтаксис, но он возвращает индекс, на котором был найден элемент, а не сам элемент.
Значение **-1** возвращается, если ничего не найдено.
Метод **arr.findLastIndex** похож на **findIndex**, но ищет справа налево, наподобие **lastIndexOf**.
### filter
Если найденных элементов может быть много, можно использовать arr.filter(fn).
Синтаксис схож с find, но filter возвращает массив из всех подходящих элементов:
```js
let results = arr.filter(function (item, index, array) {
// если `true` -- элемент добавляется к results и перебор продолжается
// возвращается пустой массив в случае, если ничего не найдено
});
```
## Преобразование массива
### map
Он вызывает функцию для каждого элемента массива и возвращает массив результатов выполнения этой функции.
```js
let result = arr.map(function (item, index, array) {
// возвращается новое значение вместо элемента
});
```
### sort(fn)
Вызов arr.sort() сортирует массив на месте, меняя в нём порядок элементов.
Он также возвращает отсортированный массив, но обычно возвращаемое значение игнорируется, так как изменяется сам arr.
***По умолчанию элементы сортируются как строки.***
Чтобы использовать наш собственный порядок сортировки, нам нужно предоставить функцию в качестве аргумента arr.sort()
```js
function compare(a, b) {
if (a > b) return 1; // если первое значение больше второго
if (a == b) return 0; // если равны
if (a < b) return -1; // если первое значение меньше второго
}
```
💥 ***Функция сравнения может вернуть любое число***
Лучше использовать стрелочные функции
```js
arr.sort( (a, b) => a - b );
```
Используйте localeCompare для строк
### reverse
Метод arr.reverse меняет порядок элементов в arr на обратный и возвращает новый массив.
### split и join
**str.split(delim)** - разбивает строку на массив по заданному разделителю delim.
**arr.join(glue)** - создаёт строку из элементов arr, вставляя glue между ними.
### reduce/reduceRight
Функция применяется по очереди ко всем элементам массива и «переносит» свой результат на следующий вызов.
Аргументы:
- **accumulator** результат предыдущего вызова этой функции, равен initial при первом вызове (если передан initial),
- **item** очередной элемент массива,
- **index** его позиция,
- **array** сам массив.
```js
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert( result ); // 15
```
### Array.isArray
Массивы не образуют отдельный тип данных, так как основаны на объектах, поэтому typeof не может отличить простой объект от массива.
### Большинство методов поддерживают «thisArg»
Все методы за исключением sort(fn)
Значение параметра thisArg становится this для func.
### Другие функции
- arr.some(fn)/arr.every(fn) проверяет массив.
- arr.fill(value, start, end) заполняет массив повторяющимися value, начиная с индекса start до end.
- arr.copyWithin(target, start, end) копирует свои элементы, начиная с позиции start и заканчивая end, в себя, на позицию target (перезаписывая существующие).
- arr.flat(depth)/arr.flatMap(fn) создаёт новый плоский массив из многомерного массива.

View File

@@ -0,0 +1,97 @@
---
sidebar_position: 6
---
# Map и Set
Отличия от обычного объекта **`Object`**:
- Что угодно может быть ключом, в том числе и объекты.
- Есть дополнительные методы, свойство **`size`**.
**`Set`** коллекция уникальных значений, так называемое «множество».
## Map
**`Map`** это коллекция ключ/значение, как и **`Object`**. Но основное отличие в том, что **`Map`** позволяет использовать ключи любого типа.
Методы и свойства:
- **new Map()** создаёт коллекцию.
- **map.set(key, value)** записывает по ключу key значение value.
- **map.get(key)** возвращает значение по ключу или undefined, если ключ key отсутствует.
- **map.has(key)** возвращает true, если ключ key присутствует в коллекции, иначе false.
- **map.delete(key)** удаляет элемент (пару «ключ/значение») по ключу key.
- **map.clear()** очищает коллекцию от всех элементов.
- **map.size** возвращает текущее количество элементов.
💥 map[key] это не совсем правильный способ использования **`Map`** \
Поэтому нам следует использовать методы map: set, get и так далее.\
**Map может использовать объекты в качестве ключей.**
💥 Как объект **`Map`** сравнивает ключи \
Чтобы сравнивать ключи, объект **Map** использует алгоритм **SameValueZero**. Это почти такое же сравнение, что и ===, с той лишь разницей, что **NaN** считается равным **NaN**. Так что **NaN** также может использоваться в качестве ключа.
### Перебор Map
Для перебора коллекции Map есть 3 метода:
- map.keys() возвращает итерируемый объект по ключам,
- map.values() возвращает итерируемый объект по значениям,
- map.entries() возвращает итерируемый объект по парам вида [ключ, значение], этот вариант используется по умолчанию в for..of.
💥 Используется порядок вставки
В отличие от обычных объектов **`Object`**, в **`Map`** перебор происходит в том же порядке, в каком происходило добавление элементов.
Map имеет встроенный метод **`forEach`**, схожий со встроенным методом массивов **`Array`**
### Object.entries: Map из Object
При создании Map мы можем указать массив (или другой итерируемый объект) с парами ключ-значение для инициализации
```js
// массив пар [ключ, значение]
let map = new Map([
['1', 'str1'],
[1, 'num1'],
[true, 'bool1']
]);
alert( map.get('1') ); // str1
```
Если у нас уже есть обычный объект, и мы хотели бы создать Map из него, то поможет встроенный метод Object.entries(obj), который получает объект и возвращает массив пар ключ-значение для него, как раз в этом формате.
```js
let obj = {
name: "John",
age: 30
};
let map = new Map(Object.entries(obj));
alert( map.get('name') ); // John
```
### Object.fromEntries: Object из Map
Мы можем использовать **`Object.fromEntries`**, чтобы получить обычный объект из **`Map`**.
```js
let map = new Map();
map.set('banana', 1);
map.set('orange', 2);
map.set('meat', 4);
let obj = Object.fromEntries(map.entries()); // создаём обычный объект (*)
alert(obj.orange); // готово! obj = { banana: 1, orange: 2, meat: 4 }
```
## Set
Объект Set это особый вид коллекции: «множество» значений (без ключей), где каждое значение может появляться только один раз.
Его основные методы это:
- **`new Set(iterable)`** создаёт **`Set`**, и если в качестве аргумента был предоставлен итерируемый объект (обычно это массив), то копирует его значения в новый **`Set`**.
- **`set.add(value)`** добавляет значение (если оно уже есть, то ничего не делает), возвращает тот же объект set.
- **`set.delete(value)`** удаляет значение, возвращает **`true`**, если **`value`** было в множестве на момент вызова, иначе **`false`**.
- **`set.has(value)`** возвращает **`true`**, если значение присутствует в множестве, иначе **`false`**.
- **`set.clear()`** удаляет все имеющиеся значения.
- **`set.size`** возвращает количество элементов в множестве.
### Перебор объекта Set
Мы можем перебрать содержимое объекта set как с помощью метода for..of, так и используя forEach:
**`Set`** имеет те же встроенные методы, что и **`Map`**:
- **`set.values()`** возвращает перебираемый объект для значений,
- **`set.keys()`** то же самое, что и **`set.values()`**, присутствует для обратной совместимости с **`Map`**,
- **`set.entries()`** возвращает перебираемый объект для пар вида [значение, значение], присутствует для обратной совместимости с **`Map`**.
-

View File

@@ -0,0 +1,63 @@
---
sidebar_position: 7
---
**`WeakMap`** это **`Map`**-подобная коллекция, позволяющая использовать в качестве ключей только объекты, и автоматически удаляющая их вместе с соответствующими значениями, как только они становятся недостижимыми иными путями.
**`WeakSet`** это **`Set`**-подобная коллекция, которая хранит только объекты и удаляет их, как только они становятся недостижимыми иными путями.
Обе этих структуры данных не поддерживают методы и свойства, работающие со всем содержимым сразу или возвращающие информацию о размере коллекции. Возможны только операции на отдельном элементе коллекции.
**`WeakMap`** и **`WeakSet`** используются как вспомогательные структуры данных в дополнение к «основному» месту хранения объекта. Если объект удаляется из основного хранилища и нигде не используется, кроме как в качестве ключа в **`WeakMap`** или в **`WeakSet`**, то он будет удалён автоматически.
## WeakMap
Первое его отличие от Map в том, что ключи в WeakMap должны быть объектами, а не примитивными значениями
Теперь, если мы используем объект в качестве ключа и если больше нет ссылок на этот объект, то он будет удалён из памяти (и из объекта WeakMap) автоматически.
WeakMap не поддерживает перебор и методы keys(), values(), entries(), так что нет способа взять все ключи или значения из неё.
В WeakMap присутствуют только следующие методы:
- weakMap.get(key)
- weakMap.set(key, value)
- weakMap.delete(key)
- weakMap.has(key)
К чему такие ограничения? Из-за особенностей технической реализации. Если объект станет недостижим (как объект john в примере выше), то он будет автоматически удалён сборщиком мусора. Но нет информации, в какой момент произойдёт эта очистка.
Решение о том, когда делать сборку мусора, принимает движок JavaScript. Он может посчитать необходимым как удалить объект прямо сейчас, так и отложить эту операцию, чтобы удалить большее количество объектов за раз позже. Так что технически количество элементов в коллекции WeakMap неизвестно. Движок может произвести очистку сразу или потом, или сделать это частично. По этой причине методы для доступа ко всем сразу ключам/значениям недоступны.
В основном, WeakMap используется в качестве дополнительного хранилища данных.
Если мы работаем с объектом, который «принадлежит» другому коду, может быть даже сторонней библиотеке, и хотим сохранить у себя какие-то данные для него, которые должны существовать лишь пока существует этот объект, то WeakMap как раз то, что нужно.
Мы кладём эти данные в WeakMap, используя объект как ключ, и когда сборщик мусора удалит объекты из памяти, ассоциированные с ними данные тоже автоматически исчезнут.
## WeakSet
Коллекция WeakSet ведёт себя похоже:
- Она аналогична Set, но мы можем добавлять в WeakSet только объекты (не примитивные значения).
- Объект присутствует в множестве только до тех пор, пока доступен где-то ещё.
- Как и Set, она поддерживает add, has и delete, но не size, keys() и не является перебираемой.
Будучи «слабой» версией оригинальной структуры данных, она тоже служит в качестве дополнительного хранилища. Но не для произвольных данных, а скорее для значений типа «да/нет». Присутствие во множестве WeakSet может что-то сказать нам об объекте.
```js
let visitedSet = new WeakSet();
let john = { name: "John" };
let pete = { name: "Pete" };
let mary = { name: "Mary" };
visitedSet.add(john); // John заходил к нам
visitedSet.add(pete); // потом Pete
visitedSet.add(john); // John снова
// visitedSet сейчас содержит двух пользователей
// проверим, заходил ли John?
alert(visitedSet.has(john)); // true
// проверим, заходила ли Mary?
alert(visitedSet.has(mary)); // false
john = null;
// структура данных visitedSet будет очищена автоматически (объект john будет удалён из visitedSet)
```

View File

@@ -0,0 +1,38 @@
---
sidebar_position: 8
---
# keys, values, entries
.keys(), .values(), .entries(). Универсальные методы, и существует общее соглашение использовать их для структур данных. Если бы мы делали собственную структуру данных, нам также следовало бы их реализовать.
Методы поддерживаются для структур:
- Map
- Set
- Array
### Object.keys, values, entries
Для простых объектов доступны следующие методы:
- **`Object.keys(obj)`** возвращает массив ключей.
- **`Object.values(obj)`** возвращает массив значений.
- **`Object.entries(obj)`** возвращает массив пар [ключ, значение].
Объекты являются основой всех сложных структур в JavaScript. У нас может быть объект `data`, который реализует свой собственный метод data.values(). И мы всё ещё можем применять к нему стандартный метод `Object.values(data)`.
```js
let user = {
name: "John",
age: 30
};
```
- `Object.keys(user) = ["name", "age"]`
- `Object.values(user) = ["John", 30]`
- `Object.entries(user) = [ ["name","John"], ["age",30] ]`
💥 ***Object.keys/values/entries игнорируют символьные свойства***\
Так же, как и цикл for..in, эти методы игнорируют свойства, использующие Symbol(...) в качестве ключей.
### Трансформации объекта
У объектов нет множества методов, которые есть в массивах, например map, filter и других.
Если мы хотели бы их применить, то можно использовать Object.entries с последующим вызовом Object.fromEntries:
1. Вызов **`Object.entries(obj)`** возвращает массив пар ключ/значение для obj.
2. На нём вызываем методы массива, например, **`map`**.
3. Используем `Object.fromEntries(array)` на результате, чтобы преобразовать его обратно в объект.

View File

@@ -0,0 +1,119 @@
---
sidebar_position: 9
---
# Деструктурирующее присваивание
Деструктуризация позволяет разбивать объект или массив на переменные при присвоении.
Полный синтаксис для объекта:
```js
let {prop : varName = defaultValue, ...rest} = object
```
Полный синтаксис для массива:
```js
let [item1 = defaultValue, item2, ...rest] = array
```
Можно извлекать данные из вложенных объектов и массивов, для этого левая сторона должна иметь ту же структуру, что и правая.
### Деструктуризация массива
```js
let arr = ["Ilya", "Kantor"]; // у нас есть массив с именем и фамилией
let [firstName, surname] = arr; // деструктурирующее присваивание
```
💥 «Деструктуризация» не означает «разрушение».
#### Работает с любым перебираемым объектом с правой стороны
```js
let [a, b, c] = "abc";
let [one, two, three] = new Set([1, 2, 3]);
```
#### Присваивайте чему угодно с левой стороны
```js
let user = {};
[user.name, user.surname] = "Ilya Kantor".split(' ');
alert(user.name, user.surname); // Ilya Kantor
```
#### Цикл с .entries()
```js
let user = {
name: "John",
age: 30
};
for (let [key, value] of Object.entries(user)) { // цикл по ключам и значениям
alert(`${key}:${value}`); // name:John, затем age:30
}
```
#### Трюк обмена переменных
```js
let guest = "Jane";
let admin = "Pete";
[guest, admin] = [admin, guest];// Давайте поменяем местами значения: сделаем guest = "Pete", а admin = "Jane"
alert(`${guest} ${admin}`); // Pete Jane (успешно заменено!)
```
### Остаточные параметры «…»
```js
let [name1, name2, ...rest] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];
// rest это массив элементов, начиная с 3-го
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
```
### Значения по умолчанию
Если мы хотим, чтобы значение «по умолчанию» заменило отсутствующее, мы можем указать его с помощью =
```js
// значения по умолчанию
let [name = "Guest", surname = "Anonymous"] = ["Julius"];
alert(name); // Julius (из массива)
alert(surname); // Anonymous (значение по умолчанию)
```
Значения по умолчанию могут быть гораздо более сложными выражениями или даже функциями. Они выполняются, только если значения отсутствуют.
### Деструктуризация объекта
Деструктурирующее присваивание также работает с объектами.
```js
let options = {
title: "Menu",
width: 100,
height: 200
};
// { sourceProperty: targetVariable }
let {width: w, height: h, title} = options;
// width -> w
// height -> h
// title -> title
alert(title); // Menu
alert(w); // 100
alert(h); // 200
```
### Остаток объекта «…»
```js
let options = {
title: "Menu",
height: 200,
width: 100
};
// title = свойство с именем title
// rest = объект с остальными свойствами
let {title, ...rest} = options;
// сейчас title="Menu", rest={height: 200, width: 100}
alert(rest.height); // 200
alert(rest.width); // 100
```
### Умные параметры функций
```js
function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
// ...
}
```

View File

@@ -0,0 +1,71 @@
---
sidebar_position: 10
---
# Дата и время
- Дата и время в JavaScript представлены объектом `Date`. Нельзя создать «только дату» или «только время»: объекты `Date` всегда содержат и то, и другое.
- Счёт месяцев начинается с нуля (да, январь это нулевой месяц).
- Дни недели в `getDay()` также отсчитываются с нуля, что соответствует воскресенью.
- Объект `Date` самостоятельно корректируется при введении значений, выходящих за рамки допустимых. Это полезно для сложения/вычитания дней/месяцев/недель.
- Даты можно вычитать, и разность возвращается в миллисекундах. Так происходит, потому что при преобразовании в число объект `Date` становится таймстампом.
- Используйте `Date.now()` для быстрого получения текущего времени в формате таймстампа.
### Создание
- **`new Date()`** Без аргументов создать объект Date с текущими датой и временем
- **`new Date(milliseconds)`** Создать объект Date с временем, равным количеству миллисекунд (тысячная доля секунды), прошедших с 1 января 1970 года UTC+0.
- **`new Date(datestring)`** Если аргумент всего один, и это строка, то из неё «прочитывается» дата.
- **`new Date(year, month, date, hours, minutes, seconds, ms)`** Создать объект Date с заданными компонентами в местном часовом поясе. Обязательны только первые два аргумента.
### Получение компонентов даты
- getFullYear() - Получить год (4 цифры)
- getMonth() - Получить месяц, от 0 до 11.
- getDate() - Получить день месяца, от 1 до 31, что несколько противоречит названию метода.
- getHours(), getMinutes(), getSeconds(), getMilliseconds() - Получить, соответственно, часы, минуты, секунды или миллисекунды.
- getDay() Получить определённый день недели
- getTime() Для заданной даты возвращает таймстамп количество миллисекунд, прошедших с 1 января 1970 года UTC+0.
- getTimezoneOffset() Возвращает разницу в минутах между UTC и местным часовым поясом:
***Все вышеперечисленные методы возвращают значения в соответствии с местным часовым поясом.***
### Установка компонентов даты
- setFullYear(year, [month], [date])
- setMonth(month, [date])
- setDate(date)
- setHours(hour, [min], [sec], [ms])
- setMinutes(min, [sec], [ms])
- setSeconds(sec, [ms])
- setMilliseconds(ms)
- setTime(milliseconds) (устанавливает дату в виде целого количества миллисекунд, прошедших с 01.01.1970 UTC)
У всех этих методов, кроме setTime(), есть UTC-вариант, например: setUTCHours().
### Автоисправление даты
Автоисправление это очень полезная особенность объектов Date. Можно устанавливать компоненты даты вне обычного диапазона значений, а объект сам себя исправит.
```js
let date = new Date(2013, 0, 32); // 32 Jan 2013 ?!?
alert(date); // ...1st Feb 2013!
```
### Преобразование к числу, разность дат
Если объект Date преобразовать в число, то получим таймстамп по аналогии с date.getTime()
Важный побочный эффект: даты можно вычитать, в результате получаем разность в миллисекундах.
### Date.now()
Существует особый метод Date.now(), возвращающий текущую метку времени.
Семантически он эквивалентен new Date().getTime(), однако метод не создаёт промежуточный объект Date. Так что этот способ работает быстрее и не нагружает сборщик мусора.
### Разбор строки с датой
Метод Date.parse(str) считывает дату из строки.
Формат строки должен быть следующим: YYYY-MM-DDTHH:mm:ss.sssZ, где:
- YYYY-MM-DD это дата: год-месяц-день.
- Символ "T" используется в качестве разделителя.
- HH:mm:ss.sss время: часы, минуты, секунды и миллисекунды.
- Необязательная часть 'Z' обозначает часовой пояс в формате +-hh:mm. Если указать просто букву Z, то получим UTC+0.
Возможны и более короткие варианты, например, YYYY-MM-DD или YYYY-MM, или даже YYYY.
Вызов Date.parse(str) обрабатывает строку в заданном формате и возвращает таймстамп (количество миллисекунд с 1 января 1970 года UTC+0). Если формат неправильный, возвращается NaN.