Объекты
TypeScript
Объекты в TypeScript можно описывать с помощью ключевого слова object
. Про это ключевое слово нужно знать, но не стоит использовать. Этот тип не говорит почти ни о чём ни компилятору, ни человеку. И последнее — даже важнее.
// Плохо — ничего не знаем про содержимое объекта
const colors: object = {
red: '#F00',
green: '#0F0',
blue: '#00F'
};
Намного лучше описывать объекты так, как они есть — со всеми полями и типами данных в них. Для этого используется такая запись:
const settings: {
color: string;
delay: number;
retry: boolean;
} = {
color: '#F00',
delay: 2000,
retry: false
};
Или через type:
type TSettings = {
color: string;
delay: number;
retry: boolean;
}
const settings: TSettings = {
color: '#F00',
delay: 2000,
retry: false
};
Record
Иногда бывают задачи, где не важно знать о ключах объекта (например, они динамически добавляются и удаляются), но важно знать, что в значениях лежат только числа (например делаем счётчик чего-то). В таких случаях поможет тип Record
:
// Record<тип_ключа, тип_значения>
const counter: Record<string, number> = {
apple: 1,
orange: 8,
banana: 6,
grape: 5
};
Альтернативой Record может быть вот такая запись:
const counter: { [key: string]: number } = {
apple: 1,
orange: 8,
banana: 6,
grape: 5
};
Этот синтаксис стоит иметь в виду при работе с типами, но для продуктовых задач чаще хватает Record или явного описания объекта.
Опциональные ключи
В объектах также можно описать опциональные ключи — они могут быть, а могут не быть. Для этого используется символ ?
после ключа:
// Это ок, поля price нет в объекте
const price: { name: string; price?: number } = {
name: 'Товар1'
};
// Это ок, поле price есть и имеет тип number
const price2: { name: string; price?: number } = {
name: 'Товар1',
price: 5
};
// Не ок, тип price не попадает в number
const price3: { name: string; price?: number } = {
name: 'Товар1',
price: '5'
};
Самый основной тип данных в JS. Состоит из пар: имя-значение или ключ-значение.
Объект вызывается с помощью фигурных скобок {...} - поле объекта, в которые вставляются свойства данного объекта. Свойства в объектах перечисляются через "," присваиваются через ":", набодобие как в CSS.
Объект -> Свойство объекта -> Значение свойства (key: value)
. Если в свойстве обекта лежит функция, то она называется методом объекта.В JS по сути
ОБЪЕКТЫ === ФУНКЦИИ
, так как функция в основном возвращает объект {}
Синтаксис
{
ключ1(свойство1): значение1,
ключ2(свойство2): значение2,
ключN(свойствоN): значениеN,
}
Создание объекта
// с помощью переменной и глобального класса-конструктора (старый способ)
const a = new Object();
a.someProperty = true;
const someDynamicField = 'hasCar';
const key = 'name';
// с помощью переменной (новый способ)
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 33,
man: true,
"likes birds": true, // свойство в несколько слов
[someDynamicField]: true, // свойство-переменная в []
};
person.hasCar; // true
person[key]; // 'Evgeny'
Простые действия с объектами
Вывести отдельное свойство
Обращение к свойству объекта осуществляется через оператор доступа (
.
) или через ([]
) .Если мы будем обращаться к несуществующему свойству объекта, то ошибки не будет, а просто вернется
undefined
.person.age; // 37
person['age']; // 37
person["likes birds"]; // true
person.height; // unknown property -> return undefinedИзменить свойство
person.age = 37;
Добавить новое свойсвто
person.country = 'Russia';
Удалить свойство
delete person.age;
person['age']; // undefined
Методы объектов
Если свойством объекта является функция, то она называется методом.
// some object method
let person = {
name: 'Evgeny',
showName() {
return this.name;
},
};
person.showName(); // 'Evgeny'
this
Обращение к ТЕКУЩЕМУ объекту. this указывает на принадлежность к текущему объекту, как бы глубоко не находились его свойства.
// старая запись
var table = {
height: 100,
legsCount: 4,
changeHeight: function() {
this.height = 300;
}
};
table.changeHeight();
table.height; // 300
Вложенные объекты
let person = {
wife: {
name: 'Inna',
sername: 'Begunova',
age: 33,
}
};
console.log(person.wife.name); // 'Inna'
Деструктурирование
const { title, width } = options;
// with change value
const { title: 'anoter value', width } = options; // bad practive
// nesting
const { title, width: { fullWidth } } = options;
Проверка объектов
const someObj = {
name: 'John',
surname: 'Smith',
};
// не учитываются наследованные свойства
someObj.hasOwnProperty('name'); // true
someObj.hasOwnProperty('surname'); // true
someObj.hasOwnProperty('age'); // false
// учитываются наследованные свойства
'name' in someObj; // true
'age' in someObj; // false
// проверка через оператор доступа
someObj.name; // 'John'
someObj.age; // undefined
Сравнение объектов
Функциии - это тоже объекты. Можно создавать ссылки на объекты и сравнивать.
function a() {};
const b = a;
console.log(a === b); // true
console.log([b].includes(a)); // true
const callback1 = () => {
console.log('Event emitted');
}
const callback2 = () => {
console.log('Event emitted');
}
const b1 = callback1;
const b2 = callback2;
// сравнение объектов
b1 === callback1; // true
b1 === callback2; // false - так как разные переменные
b2 === callback1; // false - так как разные переменные
b2 === callback2; // true
// так как анонимная функция не содержит ссылки и поэтому будут не равны
callback !== () => console.log('Event emitted');;
с помощью Object.is
const person1 = {
name: 'Evgeny',
sername: 'Leukhin',
age: 37,
};
const person2 = person1;
const isEqual = Object.is(person1, person2); // true
Объекты-ссылки
const someObj = {
name: 'John',
surname: 'Smith',
};
const someObj2 = someObj;
const someObj3 = someObj;
// ссылки совпадают
someObj === someObj2; // true
someObj === someObj3; // true
someObj2 === someObj3; // true
// при изменеии каких-ли свойств, будет изменение у ссылки
// и поменяется во всех копиях
someObj2.age = 37;
someObj2.age; // 37
someObj3.age; // 37
someObj.age; // 37
Spread оператор
Исползуется для копирования свойств объекта и при сравнении этих объектов не будет общей ссылки.
const someObj = {
name: 'John',
surname: 'Smith',
};
const someObj2 = {
...someObj,
};
someObj === someObj2; // false
let originalObject = {name: "John", age: 30, size: "XL"};
// в переменную rest - запишутся все остальные свойства (rest = { size: 'XL' })
// rest - остальное
let {name, age, ...rest} = originalObject;
let newObject = {name, age, gender: "male", ...rest};
console.log(newObject); // Выведет в консоль {name: "John", age: 30, gender: "male", size: "XL"}
JSON
React apps works with JSON API.
JSON является синтаксисом для сериализации объектов, массивов, чисел, строк логических значений и значения null. Он основывается на синтаксисе JavaScript, однако всё же отличается от него: не каждый код на JavaScript является JSON, и не каждый JSON является кодом на JavaScript.
{
"some-prop1": 123,
"some-prop2": [...],
"some-prop3": {},
"some-prop4": "String",
}
Функции, создающие объекты
Название аргументов будет являться названием свойств объекта, если использовать сокращенную запись
function makeUser(name, age) {
return { name, age };
}
const user1 = makeUser('John', 33);
user1; // { name: 'John', age: 33 }
Optional chaining
Если будет обращение к несуществующему вложенному полю несуществующего поля, чтобы не возникало краш-ошибки нужно пользоваться optional chaining.
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 33,
// wife: {
// name: 'Inna',
// surname: 'Begunova',
// }
};
// обращаемся к несуществующему полю на первом уровне
person.sister; // undefined - ошибки не будет
// обращаемся к несуществующему полю на первом уровне
person.sister.age; // Uncaught TypeError: Cannot read properties of undefined (reading 'name')
// c optional chaining
person.sister?.age; // undefined
person.sister?.[age]; // undefined
Object.create
Более гибкое создание объекта.
__proto__
- особое свойство всех объектов, в котором нельзя что-либо изменять. Содержит много встроенных свойств.
Можно создавать объекты-прототипы
// с помощью класса Object принимает объект прототип
// создание объекта с наследуемыми свойствами в прототипе
const b = Object.create(
// поля прототипы (запишутся в __proto__)
{ x: 10, y: 20 },
// реальные поля
{
name: { value: 'John' },
surname: { value: 'Smith' },
}
);
Object.assign
Создание нового объекта по подобию другого.
// исходный объект
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 33,
};
// новый объект
const person2 = Object.assign(person, {
age: 37, // переписываем поле
});
person2.age = 37; // не перепишет person.age
// создание нового объекта + добавление новых полей
const person3 = Object.assign(person, { city: 'Omsk', region: 55 }); // { name: 'Evgeny', sername: 'Leukhin', age: 33, city: 'Omsk', region: 55 }
Object.keys, Object.values и Object.entries
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 37,
};
// получить массив из названий полей
Object.keys(person); // ['name', 'sername', 'age']
// получить массив значений
Object.values(person); // ['Evgeny', 'Leukhin', 37]
// получить массив массивов
Object.entries(person);
// (2) ['name', 'Evgeny']
// (2) ['sername', 'Leukhin']
// (2) ['age', 33]
Object.freeze
"Заморозить" объект от изменений. Нельзя изменять\добавлять\удалять.
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 37,
};
Object.freeze(person);
person.age = 33; // пытаемся изменить
person.age; // 37 (не изменилось)
Object.seal
Можно изменять, но нельзя добавлять\удалять.
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 37,
};
Object.seal(person);
person.age = 33; // пытаемся изменить
person.email = 'some@email.ru'; // пытаемся добавить новое свойство
person.age; // 33 (изменилось)
person.email; // undefined (не добавилось)
Обработка объектов циклом for
const person = {
name: 'Evgeny',
sername: 'Leukhin',
age: 37,
};
const keys = Object.keys(person); // ключи
const values = Object.values(person); // значчения
const entries = Object.entries(person); // массивы [ключ, значение]
// вывод всех названий полей
for (const key of keys) {
console.log(key);
}
// вывод всех значчений полей
for (const value of values) {
console.log(value);
}
// вывод всех ключей и значений
for (const [key, value] of entries) {
console.log(key, value);
}