update objects
This commit is contained in:
@@ -87,7 +87,7 @@ alert(obj.__proto__); // [object Object], значение - это объект
|
||||
|
||||
В отличие от многих других языков, особенность JavaScript-объектов в том, что можно получить доступ к любому свойству. Даже если свойства не существует – ошибки не будет!
|
||||
|
||||
При обращении к свойству, которого нет, возвращается undefined. Это позволяет просто проверить существование свойства:
|
||||
При обращении к свойству, которого нет, возвращается **undefined**. Это позволяет просто проверить существование свойства:
|
||||
```js
|
||||
let user = {};
|
||||
|
||||
|
||||
76
docs/javascript/objects/02-copying-objects.md
Normal file
76
docs/javascript/objects/02-copying-objects.md
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Копирование объектов и ссылки
|
||||
|
||||
💥 ***При копировании переменной объекта копируется ссылка, но сам объект не дублируется.***
|
||||
```js
|
||||
let user = { name: 'John' };
|
||||
|
||||
let admin = user;
|
||||
|
||||
admin.name = 'Pete'; // изменено по ссылке из переменной "admin"
|
||||
|
||||
alert(user.name); // 'Pete', изменения видны по ссылке из переменной "user"
|
||||
```
|
||||
|
||||
## Сравнение по ссылке
|
||||
Два объекта равны только в том случае, если это один и тот же объект.
|
||||
|
||||
***a*** и ***b*** ссылаются на один и тот же объект, поэтому они равны:
|
||||
```js
|
||||
let a = {};
|
||||
let b = a; // копирование по ссылке
|
||||
|
||||
alert( a == b ); // true, обе переменные ссылаются на один и тот же объект
|
||||
alert( a === b ); // true
|
||||
```
|
||||
|
||||
Здесь два независимых объекта не равны, даже если они выглядят одинаково (оба пусты):
|
||||
```js
|
||||
let a = {};
|
||||
let b = {}; // два независимых объекта
|
||||
|
||||
alert( a == b ); // false
|
||||
```
|
||||
|
||||
## Клонирование и объединение, Object.assign
|
||||
Есть 2 вида копирования shallow - поверхностное и deep - глубокое
|
||||
|
||||
#### Перебор всех свойств объекта через цикл или рекурсию (shallow / deep)
|
||||
```js
|
||||
let user = {
|
||||
name: "John",
|
||||
age: 30
|
||||
};
|
||||
|
||||
let clone = {}; // новый пустой объект
|
||||
|
||||
// давайте скопируем все свойства user в него
|
||||
for (let key in user) {
|
||||
clone[key] = user[key];
|
||||
}
|
||||
|
||||
// теперь clone это полностью независимый объект с тем же содержимым
|
||||
clone.name = "Pete"; // изменим в нём данные
|
||||
|
||||
alert( user.name ); // все ещё John в первоначальном объекте
|
||||
```
|
||||
Готовая реализация, через например _.cloneDeep(obj) из библиотеки JavaScript lodash.
|
||||
|
||||
#### Метод Object.assign (shallow)
|
||||
```js
|
||||
Object.assign(dest, [src1, src2, src3...])
|
||||
```
|
||||
#### Оператор расширения \{...obj\} (shallow)
|
||||
Метод тоже делает поверхностное копирование, для глубокого надо обойти объект рекурсивно
|
||||
|
||||
#### JsonParse (deep)
|
||||
Cамый простой способ скопировать объект со всеми уровнями вложенности, не копирует методы:
|
||||
```js
|
||||
let clone = JSON.parse(JSON.stringify(obj))
|
||||
```
|
||||
|
||||
#### Метод structuredClone (deep)
|
||||
Мы можем использовать глобальный метод ***structuredClone()***, который позволяет сделать полную копию объекта. К сожалению он поддерживается только современными браузерами.
|
||||
40
docs/javascript/objects/03-methods-this.md
Normal file
40
docs/javascript/objects/03-methods-this.md
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Методы объекта, "this"
|
||||
|
||||
***Для доступа к информации внутри объекта метод может использовать ключевое слово this.***
|
||||
```js
|
||||
let user = {
|
||||
name: "John",
|
||||
|
||||
sayHi() {
|
||||
alert(this.name); // "this" - это "текущий объект".
|
||||
}
|
||||
};
|
||||
```
|
||||
### «this» не является фиксированным
|
||||
В JavaScript ключевое слово «this» ведёт себя иначе, чем в большинстве других языков программирования. Его можно использовать в любой функции, даже если это не метод объекта.
|
||||
|
||||
❗ ***Вызов без объекта: this == undefined***
|
||||
|
||||
В строгом режиме ("use strict") в таком коде значением `this` будет являться `undefined`. Если мы попытаемся получить доступ к this.name – это вызовет ошибку.
|
||||
|
||||
В нестрогом режиме значением `this` в таком случае будет глобальный объект (`window` в браузерe, мы вернёмся к этому позже в главе Глобальный объект). Это – исторически сложившееся поведение `this`, которое исправляется использованием строгого режима ("use strict").
|
||||
|
||||
Обычно подобный вызов является ошибкой программирования. Если внутри функции используется this, тогда она ожидает, что будет вызвана в контексте какого-либо объекта.
|
||||
|
||||
❗ ***Последствия свободного this***
|
||||
|
||||
В JavaScript `this` является «свободным», его значение вычисляется в момент вызова метода и не зависит от того, где этот метод был объявлен, а скорее от того, какой объект вызывает метод (какой объект стоит «перед точкой»).
|
||||
|
||||
Эта концепция вычисления `this` в момент исполнения имеет как свои плюсы, так и минусы. С одной стороны, функция может быть повторно использована в качестве метода у различных объектов (что повышает гибкость).
|
||||
|
||||
### У стрелочных функций нет «this»
|
||||
Стрелочные функции особенные: у них нет своего «собственного» `this`. Если мы ссылаемся на `this` внутри такой функции, то оно берётся из внешней «нормальной» функции.
|
||||
|
||||
1. Методы могут ссылаться на объект через `this`.
|
||||
2. Значение `this` определяется во время исполнения кода.
|
||||
- При объявлении любой функции в ней можно использовать `this`, но этот `this` не имеет значения до тех пор, пока функция не будет вызвана.
|
||||
- Когда функция вызывается синтаксисом «метода» – ***object.method()***, значением `this` во время вызова является `object`.
|
||||
34
docs/javascript/objects/04-constructor-new-op.md
Normal file
34
docs/javascript/objects/04-constructor-new-op.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Конструктор, оператор "new"
|
||||
|
||||
### Функция-конструктор
|
||||
Функции-конструкторы технически являются обычными функциями. Но есть два соглашения:
|
||||
|
||||
1. Имя функции-конструктора должно начинаться с большой буквы.
|
||||
2. Функция-конструктор должна выполняться только с помощью оператора "new".
|
||||
|
||||
|
||||
Когда функция вызывается как new User(...), происходит следующее:
|
||||
|
||||
1. Создаётся новый пустой объект, и он присваивается `this`.
|
||||
2. Выполняется тело функции. Обычно оно модифицирует `this`, добавляя туда новые свойства.
|
||||
3. Возвращается значение `this`.
|
||||
|
||||
Другими словами, new User(...) делает что-то вроде:
|
||||
```js
|
||||
function User(name) {
|
||||
// this = {}; (неявно)
|
||||
|
||||
// добавляет свойства к this
|
||||
this.name = name;
|
||||
this.isAdmin = false;
|
||||
|
||||
// return this; (неявно)
|
||||
}
|
||||
```
|
||||
Итого:
|
||||
- Функции-конструкторы или просто конструкторы, являются обычными функциями, но существует общепринятое соглашение именовать их с заглавной буквы.
|
||||
- Функции-конструкторы следует вызывать только с помощью `new`. Такой вызов подразумевает создание пустого `this` в начале и возврат заполненного в конце.
|
||||
36
docs/javascript/objects/05-option-chaining.md
Normal file
36
docs/javascript/objects/05-option-chaining.md
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Опциональная цепочка '?.'
|
||||
Опциональная цепочка ?. останавливает вычисление и возвращает `undefined`, если значение перед ?. равно `undefined` или `null`.
|
||||
```js
|
||||
let user = {}; // пользователь без адреса
|
||||
|
||||
alert( user?.address?.street ); // undefined (без ошибки)
|
||||
```
|
||||
### Другие варианты применения: ?.(), ?.[]
|
||||
Опциональная цепочка ?. — это не оператор, а специальная синтаксическая конструкция, которая также работает с функциями и квадратными скобками.
|
||||
|
||||
Например, ?.() используется для вызова функции, которая может не существовать.
|
||||
|
||||
❗ ***Мы можем использовать ?. для безопасного чтения и удаления, но не для записи***
|
||||
|
||||
Опциональная цепочка ?. не имеет смысла в левой части присваивания.
|
||||
```js
|
||||
let user = null;
|
||||
|
||||
user?.name = "John"; // Ошибка, не работает
|
||||
// то же самое что написать undefined = "John"
|
||||
```
|
||||
|
||||
## Итого
|
||||
Синтаксис опциональной цепочки ?. имеет три формы:
|
||||
|
||||
1. **obj?.prop** – возвращает ***obj.prop*** если `obj` существует, в противном случае `undefined`.
|
||||
2. **obj?.[prop]** – возвращает ***obj[prop]*** если `obj` существует, в противном случае `undefined`.
|
||||
3. **obj.method?.()** – вызывает ***obj.method()***, если obj.method существует, в противном случае возвращает `undefined`.
|
||||
|
||||
Как мы видим, все они просты и понятны в использовании. ?. проверяет левую часть на `null/undefined` и позволяет продолжить вычисление, если это не так.
|
||||
|
||||
Цепочка ?. позволяет безопасно получать доступ к вложенным свойствам.
|
||||
44
docs/javascript/objects/06-symbol.md
Normal file
44
docs/javascript/objects/06-symbol.md
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Тип данных Symbol
|
||||
|
||||
Символ (symbol) – примитивный тип данных, использующийся для создания уникальных идентификаторов.
|
||||
|
||||
```js
|
||||
// Создаём новый символ - id
|
||||
let id = Symbol();
|
||||
```
|
||||
|
||||
При создании, символу можно дать описание (также называемое имя), в основном использующееся для отладки кода
|
||||
|
||||
Символы гарантированно уникальны. Даже если мы создадим множество символов с одинаковым описанием, это всё равно будут
|
||||
разные символы. Описание – это просто метка, которая ни на что не влияет.
|
||||
|
||||
```js
|
||||
let id1 = Symbol("id");
|
||||
let id2 = Symbol("id");
|
||||
|
||||
alert(id1 == id2); // false
|
||||
```
|
||||
|
||||
💥***Символы не преобразуются автоматически в строки***
|
||||
|
||||
#### Символы игнорируются циклом for…in
|
||||
|
||||
Свойства, чьи ключи – символы, не перебираются циклом for..in.
|
||||
|
||||
Символы имеют два основных варианта использования:
|
||||
|
||||
1. «Скрытые» свойства объектов.
|
||||
Если мы хотим добавить свойство в объект, который «принадлежит» другому скрипту или библиотеке, мы можем создать
|
||||
символ и использовать его в качестве ключа. Символьное свойство не появится в for..in, так что оно не будет нечаянно
|
||||
обработано вместе с другими. Также оно не будет модифицировано прямым обращением, так как другой скрипт не знает о
|
||||
нашем символе. Таким образом, свойство будет защищено от случайной перезаписи или использования.
|
||||
|
||||
Так что, используя символьные свойства, мы можем спрятать что-то нужное нам, но что другие видеть не должны.
|
||||
2. Существует множество системных символов, используемых внутри JavaScript, доступных как Symbol.*. Мы можем
|
||||
использовать их, чтобы изменять встроенное поведение ряда объектов. Например, в дальнейших главах мы будем
|
||||
использовать Symbol.iterator для итераторов, Symbol.toPrimitive для настройки преобразования объектов в примитивы и
|
||||
так далее.
|
||||
27
docs/javascript/objects/07-objects-to-primitives.md
Normal file
27
docs/javascript/objects/07-objects-to-primitives.md
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Преобразование объектов в примитивы
|
||||
|
||||
Преобразование объекта в примитив вызывается автоматически многими встроенными функциями и операторами, которые ожидают примитив в качестве значения.
|
||||
|
||||
Существует всего 3 типа (хинта) для этого:
|
||||
|
||||
- "string" (для alert и других операций, которым нужна строка)
|
||||
- "number" (для математических операций)
|
||||
- "default" (для некоторых других операторов, обычно объекты реализуют его как "number")
|
||||
|
||||
Спецификация явно описывает для каждого оператора, какой ему следует использовать хинт.
|
||||
|
||||
Алгоритм преобразования таков:
|
||||
|
||||
1. Сначала вызывается метод obj[Symbol.toPrimitive](hint), если он существует,
|
||||
2. В случае, если хинт равен "string"
|
||||
- происходит попытка вызвать obj.toString() и obj.valueOf(), смотря что есть.
|
||||
3. В случае, если хинт равен "number" или "default"
|
||||
- происходит попытка вызвать obj.valueOf() и obj.toString(), смотря что есть.
|
||||
|
||||
Все эти методы должны возвращать примитив (если определены).
|
||||
|
||||
На практике часто бывает достаточно реализовать только obj.toString() в качестве универсального метода для преобразований к строке, который должен возвращать удобочитаемое представление объекта для целей логирования или отладки.
|
||||
Reference in New Issue
Block a user