Основы создания объектов и работы с ними в JavaScript
Статья, в которой познакомимся с понятием объекта. Рассмотрим, как осуществляется создание собственных объектов. Разберём массив объектов и приёмы работы с ним.
Что такое объекты?
Объект – это один из типов данных в JavaScript, который предназначен для хранения коллекции различных значений и более сложных сущностей.
Всего в JavaScript существует 8 типов данных: Number
, BigInt
, String
, Boolean
, null
, undefined
, Symbol
и Object
.
Но все кроме объекта являются примитивными. При присвоении переменной значения примитивного типа, оно хранится в ней непосредственно:
// переменная mark содержит значение примитивного типа в данном случае число
let mark = 4;
// присваиваем переменной mark новое примитивное значение, а именно строку 'Good!'
mark = 'Good!';
Когда мы хотим одной переменной присвоить значение другой, содержащей примитивный тип, копирование осуществляется по значению (по английски – copy by value):
const mark = 4;
// создание newMark и присвоение ей значения переменной mark
let newMark = mark;
// присвоим newMark новое значение
newMark = 5;
console.log(mark); // 4
console.log(newMark); // 5
Здесь мы видим как происходит копирование значений примитивных типов, то есть непосредственно по значению. Если бы переменная mark
содержала объект, то процесс копирования осуществлялся бы уже не по значению. Это очень важный момент, но об этом немного позже.
Так что же такое объект? В JavaScript объект – это набор свойств «имя: значение». При этом имена ещё очень часто называют ключами. При этом значение свойства может содержать что угодно. Если в качестве значения используется функция, то такое свойство называют методом.
Объекты – это ссылочный тип. Поэтому, когда вы присваиваете объект переменной, вы на самом деле присваиваете ей не сам этот объект, а ссылку на него, которая указывает на то место в памяти компьютера, где он находится.
Литеральный синтаксис
Литеральный синтаксис объявления объекта – это один из самых простых способов его создания. Обычно он используется, когда необходимо объявить только один объект.
Литерал объекта записывается с помощью фигурных скобок {...}
, внутрь которых помещают свойства, отделенные друг от друга посредством запятой:
const person = {
firstName: 'Александр',
lastName: 'Мальцев',
age: 28,
getFullName: function() {
return `${this.firstName} ${this.lastName}`
}
}
В этом примере объект содержит четыре свойства: firstName
, lastName
, age
и getFullName
. При этом свойство getFullName
является методом, так какие его значение – это функция.
Новый формат записи методов выполняется без использования ключевого слова function
и двоеточия:
const person = {
// ...
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
Объекты в JavaScript, как и в других языках программирования, легче понять, если провести аналогию с объектами «реального мира». При этом любой объект имеет характеристики (свойства) и может выполнять некоторые задачи (методы).
Например, объект car
имеет свойства: color
, engine
и model
. Свойства – это характеристики объекта, они обычно описываются с помощью существительных и прилагательных. Также объект имеет собственные методы: drive
, park
, start
и stop
. Методы – это поведение объекта, его функции, они обычно обозначаются посредством глаголов.

// объект car
const car = {
color: 'orange',
engine: '3.6L V6',
model: 'AL3',
drive() {
console.log('driving');
},
park() {
console.log('parking');
},
start() {
console.log('starting');
},
stop() {
console.log('stopping');
}
}
Свойства
Свойства состоят из ключа и значения. Отделяется ключ от значения посредством двоеточия. Свойства подобны переменным, но в составе объекта.
Обращение к свойствам выполняется через точку или квадратные скобки:
// через точку
const firstName = person.firstName;
const lastName = person.lastName;
// через квадратные скобки, ключ в этом случае нужно указывать в виде строки
const age = person['age'];
const getFullName = person['getFullName'];
Значения, связанные с соответствующими ключами можно не только получить, но и присвоить им новые значения:
// изменим значения свойств firstName и lastName
person.firstName = 'Иван';
person.lastName = 'Михайлов';
А также добавить новые свойства объекту:
// добавим к объекту person свойство middleName со значением 'Сергеевич'
person.middleName = 'Сергеевич';
Свойствам можно устанавливать какие угодно значения. Например, присвоим свойству children
массив объектов:
person.children = [
{
name: 'Аня',
age: 8
},
{
name: 'Ваня',
age: 14
}
]
Удаление свойств из объекта осуществляется с помощью оператора delete
:
// удалим свойство middleName из объекта person
delete person.middleName;
Проверить наличия ключа в объекте можно посредством оператора in
:
'firstName' in person // true
'middleName' in person // false
Обратите внимание, что на самом деле имена свойств в объекте являются строками. Но их можно не заключать в кавычки, как мы это делали выше. Но, это допустимо только в том случае, если они составлены по правилам именования переменных.
Имена свойств, которые составлены не по правилам именования переменных:
const someObj = {
'': 1, // имя является пустой строкой
'author of post': 'Алексей', // имя состоит из нескольких слов
}
Обратиться к таким свойствам только с помощью квадратных скобок:
// получим значения свойства, имя которой является пустой строкой
const value = someObj[''];
Если ключ содержится в переменной, то получить значение этого свойства можно только через квадратные скобки:
const key = 'author of post';
const value = someObj[key];
Но именовать свойства не по правилам не рекомендуется. Также не рекомендуется использовать в качестве ключей зарезервированные слова JavaScript, несмотря на то, что это допускается.
Методы
Методы, как мы уже отмечали выше – это свойства, у которых значение является функцией. Обращение к ним осуществляется также как к свойствам, то есть через точку или с использованием квадратных скобок:
const person = {
firstName: 'Александр',
lastName: 'Мальцев',
age: 28,
getFullName() {
console.log(`${this.firstName} ${this.lastName}`);
}
}
// создадим переменную getFullName и присвоим ей метод getFullName
const getFullName = person.getFullName;
// тоже самое только через квадратные скобки
// const getFullName = person['getFullName'];
Но, так как методы – это функции, то их соответственно можно вызвать. Методы мы для этого и создаём, чтобы потом их можно было вызывать. Вызов метода выполняется также как функции, т.е. с использованием круглых скобок:
// получим метод и присвоим его переменной getFullName
const getFullName = person.getFullName;
// вызовем метод
getFullName();
// или сразу
person.getFullName();
person['getFullName']();
Кроме выполнения действий методы всегда возвращают значения. В данном примере вызов getFullName()
возвращает значение undefined
, т.к. в нём мы явно не прописали инструкцию return
. В этом случае не явно возвращается undefined
:
console.log(getFullName()); // undefined
Краткая запись свойств
Очень часто в коде мы переменные используем в качестве значений свойств с тем же именем. Когда имя свойства совпадает с названием переменной мы эту запись можем сделать краткой:
// функция, возвращающая объект
const createRect = (width, height) => {
// возвращаем объект
return {
width, // вместо width: width
height, // вместо height: height
calcArea() {
return this.width * this.height;
}
}
}
// вызываем функцию и присваиваем возвращённый ей объект переменной rect
const rect = createRect(10, 15);
console.log(rect.calcArea()); // 150
Вычисляемые свойства
В JavaScript имя свойства может быть вычисляемым. То есть для задания имени можно использовать выражение, результат вычисления которого и будет это имя. Указывать вычисляемое свойство необходимо в квадратных скобках []
:
const key = 'url';
const app = {
name: 'Yandex',
[key]: 'https://yandex.ru/', // имя свойства будет взято из переменной key
};
console.log(app.url); // 'https://yandex.ru/'
Пример вычисляемого свойства, а точнее метода с более сложным выражением:
const key = 'url';
const app = {
name: 'Yandex',
[key]: 'https://yandex.ru/',
['get' + key.toUpperCase()]() {
return this[key];
}
};
console.log(app.getURL()); // 'https://yandex.ru/'
Копирование и сравнение объектов
Переменная, содержащая объект на самом деле содержит не сам объект, а только ссылку на него. При копировании объектов в отличие от значений примитивных типов происходит передача ссылки.
// присвоим переменной student1 объект, а точнее ссылку на него
const student1 = { name: 'Carl' };
// присвоим объект, содержащийся в student1 переменной student2
const student2 = student1;
Теперь student1
и student2
содержат ссылки, указывающие на один и тот же объект.
Изменим значение name
, используя student2
:
student2.name = 'Nelly';
Получим значение name
через student1
:
console.log(student1.name); // Nelly
А что если нам необходимо скопировать не саму ссылку, а создать новый объект с такими же свойствами?
const student3 = {};
for (const key in student1) {
student3[key] = student1[key];
}
// student3 содержит клон объекта student1
student3.name = 'Thyra';
// в student1 значение name осталось прежним
console.log(student1.name); // Nelly
Другой способ скопировать свойства – это воспользоваться методом Object.assign()
:
// скопируем все свойства из student1 в {}, а затем присвоим его student4
const student4 = Object.assign({}, student1);
Object.assign()
позволяет скопировать свойства из множества объектов. Объект, в который нужно скопировать указывается в качестве первого аргумента, а те из которых – после него:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // {a: 1, b: 2, c: 3}
Сравнение объектов выполняется по ссылкам:
let objA = {};
let objB = objA;
let objC = {};
console.log( objA === objB ); // true, т.к. переменные содержат одну и ту же ссылку
console.log( objA === objC ); // false, т.к. переменные содержат разные ссылки (оба объекта пусты, но это разные объекты)
Свойства объектов и их конфигурация
До этого времени мы рассматривали свойства как пары «ключ: значение».
Но свойство кроме значения (value
) имеет специальные флаги:
writable
– доступно ли свойство для изменения;enumerable
– доступно ли свойство для перебора в циклах;configurable
– доступно ли свойство для настройки и удаления.
Когда мы создаем литерал объекта, то все эти специальные флаги у свойства имеют значение true
. Получить полное описание свойства можно с помощью метода Object.getOwnPropertyDescriptor
:
const flower = {
name: 'rose',
color: 'red'
}
const descriptor = Object.getOwnPropertyDescriptor(flower, 'name');
console.log(descriptor);

Как вы наверно уже поняли, этот метод позволяет получить полное описание одного свойства. Для этого в Object.getOwnPropertyDescriptor
мы должны в качестве первого аргумента передать объект, содержащий это свойство, а посредством второго – его само.
Получить описание сразу всех свойств объекта можно с помощью статического метода Object.getOwnPropertyDescriptors
:
const descriptors = Object.getOwnPropertyDescriptors(flower);
console.log(descriptors);

Для того чтобы установить новые значения флагам конкретному свойству объекта необходимо использовать метод Object.defineProperty
. Например, сделаем свойство name
доступным только для чтения:
Object.defineProperty(flower, 'name', {
writable: false
});
// попробуем изменить значение свойства name
flower.name = 'lily';
console.log(flower); // { name: 'rose', color: 'red' }

В этом примере свойство name
мы сделали не доступным для изменения. Для этого мы флагу writable
установили значение false
.
Для определения сразу нескольких свойств можно применять метод Object.defineProperties
:
Object.defineProperties(flower,
name: { writable: false, configurable: false },
color: { enumerable: false }
);
Так как свойству color
мы установили флаг enumerable: false
, то теперь оно не будет доступно для перебора:
for (let key in flower) {
console.log(key);
}

Так же этого свойства не будет в массиве ключей, который возвращает метод Object.keys
:
console.log(Object.keys(flower)); // ['name']
Если свойству установить флаг configurable: false
, то оно становится не конфигурируемым. Такое свойство нельзя будет удалить и его флагам нельзя будет установить новые значения. Таким свойствам мы сделали name
.
При попытке установить этому свойству новые значения флагам мы получим ошибку:

Также мы не можем удалить это свойство:
delete flower.name; // false
console.log(flower); // {name: 'rose', color: 'red'}
Методы Object.defineProperty
и Object.defineProperties
можно использовать для добавления новых свойств объекту:
const city = {};
Object.defineProperties(city, {
name: {value: 'New York', enumerable: true, writable: true},
area: {value: 1223.59, enumerable: true, writable: true},
});
console.log(Object.getOwnPropertyDescriptors(city));

Когда мы добавляем новые свойства с помощью этих методов, все флаги имеют по умолчанию значение false
. Так как в этом примере мы пропустили флаг configurable
для всех свойств, то он у всех них имеет значение false
, то все эти свойства являются не конфигурируемыми.
Динамические свойства
В JavaScript кроме обычных свойств имеются ещё динамические. Динамическое свойство похоже на обычное, но по факту представляет собой комбинацию сеттера и геттера.
Геттер – это метод, который выполняется, когда мы хотим получить значение динамического свойства. Он не имеет параметров и возвращает значение, которое и будет значением этого свойства.
Сеттер – это метод, который выполняется, когда мы хотим присвоить значение динамическому свойству. Он имеет один параметр, который получает это значение. Далее это значение мы можем присвоить некоторому свойству или выполнить какие-либо другие действия.
При литеральном объявлении объекта они обозначаются с помощью get
и set
:
const lang = {
history: [],
// сеттер
get current() {
return this.history.length ? this.history[this.history.length - 1] : null;
},
// геттер
set current(value) {
this.history.push(value);
}
}
console.log(lang.current);
lang.current = 'ru';
console.log(lang.current); // ru
lang.current = 'en';
console.log(lang.current); // en
В этом примере мы создали динамическое свойство current
. Геттер выполняется при чтении значения этого свойства, а сеттер – при записи.
У динамического свойства необязательно должны быть два метода. Оно может также иметь только геттер или сеттер.
Определять сеттеры и геттеры можно также с помощью Object.defineProperty
и Object.defineProperties
:
const rect = {
a: 10,
b: 15
}
Object.defineProperty(rect, 'sides', {
get() {
return `${this.a} x ${this.b}`;
},
set(value) {
[this.a, this.b] = value;
}
});
console.log(rect.sides); // '10 x 15'
rect.sides = [20, 25];
console.log(rect.sides); // '20 x 25'

Динамические свойства не имеет value
и флага writable
, но вместо этого у них есть методы get
и set
.
В этом примере создадим геттер вместе с описанием других свойств, который будет возвращать последнее сообщение:
const messages = {}
Object.defineProperties(messages, {
list: { value: [] },
add: {
value: function (item) {
this.list.push(item)
}
},
// геттер last
last: {
get() {
return this.list.length > 0 ? this.list[this.list.length - 1] : '';
}
}
});
messages.add('Green');
messages.add('Red');
console.log(messages.last); // 'Red'
Преобразование объекта в массив
В стандартном конструкторе Object
имеются методы keys
и values
с помощью которых можно очень просто трансформировать объект соответственно в массиве ключей и значений.
const car = {
brand: 'Ford',
color: 'blue'
}
const keys = Object.keys(car); // ['brand', 'color']
const values = Object.values(car); // ['Ford', 'blue']
После этого, так как это массивы мы можем очень просто выполнять любые другие действия над ними, то есть перебирать, искать нужные элементы, фильтровать и так далее.
Пример перебора объекта с помощью forEach
:
Object.keys(car).forEach((key) => {
console.log(`${key}: ${car[key]}`);
});
Если нужно перебрать только значения, то так:
Object.values(car).forEach((value) => {
console.log(value);
});
Кроме этого в Object
имеется также метод entries
, массив массивов, в котором первый элемент будет являться именем свойства, а второй значением:
const car = {
brand: 'Ford',
color: 'blue'
}
const entries = Object.entries(car); // [['brand', 'Ford'], ['color', 'blue']]
entries.forEach((item) => {
console.log(`${item[0]}: ${item[1]}`);
});
Задачи
Задача 1. Необходимо создать из имеющихся на странице заголовков <h2>
массив объектов следующего вида:
[
{ id: 'h2-1', textContent: 'Первая программа' },
{ id: 'h2-2', textContent: 'Выражения' },
...
]
Задание: найти в этом массиве максимальную длину свойства textContent
и вывести это значение в консоль.
Массив объектов – это обычный массив, элементами которого являются объекты. Здесь id
– это значение атрибута id
тега <h2>
, а text
– это его содержимое.
Для получения всех элементов с тегом <h2>
необходимо использовать метод document.querySelectorAll('h2')
, а прочитать значения, необходимые для установки id
и textContent
, можно соответственно с помощью свойств с таким же названием.
После этого необходимо перебрать массив, например, с помощью метода reduce
и найти максимальную длину заголовка.
Решение:
const maxLength = headers.reduce((max, item) => {
return item.textContent.length > max ? item.textContent.length : max;
}, 0);
console.log(maxLength);
Задача 2. Имеется массив объектов. Необходимо удалить из массива объекты, у которых значение свойства x
или y
меньше нуля.
// массив объектов
const points = [
{x: 5, y: 7},
{x: -2, y: 9},
{x: 0, y: 8},
{x: -1, y: -3}
]
Решить задачу необходимо 2 способами:
- посредством изменения оригинального массива;
- не изменяя оригинальный массив.
Пример решение задачи посредством изменения оригинального массива:
let i = points.length - 1;
while (i gt:= 0) {
if (points[i].x < 0 || points[i].y < 0) {
// points.splice(i, 1);
}
i--;
}
console.log(points); // [{x: 5, y: 7}, {x: 0, y: 8}]
Пример решения, в котором мы не изменяем оригинальный массив:
const newPoints = points.filter((value) => value.x >= 0 && value.y >= 0);
console.log(newPoints); // [{x: 5, y: 7}, {x: 0, y: 8}]
Задача 3. Имеется список статей в виде массива объектов:
const listArticles = [
{ title: "Статья 7", likes: 15 },
{ title: "Статья 1", likes: 10 },
{ title: "Статья 5", likes: 3 },
{ title: "Статья 3", likes: 20 }
];
Необходимо отсортировать массив объектов по полю likes
.
Решение:
listArticles.sort((article1, article2) => {
return article1.likes < article2.likes ? -1 : article1.likes > article2.likes ? 1 : 0;
});
Задача 4. Имеется следующий массив:
const persons = [
{ name: 'John', age: 25 },
{ name: 'Leonardo', age: 15 },
{ name: 'Kristina', age: 12 }
];
Необходимо создавать новый массив, оставить в нём только те персоны, возраст которых больше или равно 18.
Решение:
const newPersons = persons.filter((value) => value.age >= 18);
console.log(newPersons);
Задача 5. Написать стрелочную функцию, которая будет проверять является ли объект переданным ей в качестве аргумента пустым, то есть не содержит ли он собственные свойства и методы.
Решение:
const isEmpty = (obj) => {
if (typeof obj === 'object' && obj !== null) {
return Object.keys(obj).length === 0;
}
return null;
}
Примеры использования:
isEmpty({ a: 5 }); // false
isEmpty({}); // true
isEmpty(5); // null
isEmpty(null); // null
Здравствуйте спасибо большое за отличную статью. Хочу обратить ваше внимание на опечатку, в разделе "Преобразование объекта в массив" value вместо values и в первом скриншоте, где присваиваете values написано keys. Спасибо
Добрый день! Благодарю за отзыв. Спасибо за найденные опечатки.
Здравствуйте, Александр. Пыталась с Вами связаться через почту и ВК. Берёте ли Вы очень интересные и необычные проекты на Мод Х для разработки? На почту отправила подробности.
Задание 1
Реализовать класс, описывающий простой маркер. В классе
должны быть следующие компоненты:
■ поле, которое хранит цвет маркера;
■ поле, которое хранит количество чернил в маркере (в процентах);
■ метод для печати (метод принимает строку и выводит
текст соответствующим цветом; текст выводится до тех
пор, пока в маркере есть чернила; один не пробельный
символ – это 0,5% чернил в маркере).
Реализовать класс, описывающий заправляющийся маркер,
унаследовав его от простого маркера и добавив метод для заправки
маркера.
Продемонстрировать работу написанных методов.
Использовать так:
Замените «ю» на.
1) Можно ли на объекте использовать те же методы, что и на массивах, map,filter,reduce или надо преобразовывать объект в массив?
2) Можно ли удалить объект в объекте. Т.е. если условно стоит задача, находить внутри объекта a у какого из его объектов имеется свойство aaa равное 5 и удалять, но не свойство aaa, а сразу весь подобъект aa?
const a = {
aa = {
aaa: 5,
aab: 3,
},
bb = {
aaa:8,
aab: 9,
}
}
1. Если у объекта и в его цепочки прототипов нет этих методов, то их конечно вызвать нельзя. Чтобы эти методы использовать этот объект конечно нужно привести к массиву.
2. Удаление свойства осуществляется как обычно даже если оно является объектом:
В примере свойства должны отделяться от значений с помощью двоеточия:
Можно например для этого создать функцию, которая будет возвращать переданную ей строку, но уже без тегов.