Кратко
СкопированоКроме примитивных типов в JavaScript существуют и сложные — например, объект.
Объект (object) — это набор свойств. Каждое свойство состоит из названия и значения. Название может быть строкой или символом, а значение может быть любым.
Объекты в JavaScript используются повсюду, особенно для хранения данных. Для уверенной работы с объектами необходимо знать, как создавать объект, как его изменять и как читать значения свойств.
Создание объектов
СкопированоЧаще всего объекты создают с помощью литеральной записи.
Пустой объект без свойств можно создать парой фигурных скобок:
const cat = {}
const cat = {}
Когда нужно создать объект со свойствами, то их описывают внутри фигурных скобок. Свойства указываются в формате имяСвойства
, между свойствами ставится запятая:
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true}
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true }
Значением может быть другой объект или массив:
const cat = { kittens: ['Беляш', 'Михаил', 'Чарли'], favoriteToy: { name: 'мячик', size: 'маленький', },}
const cat = { kittens: ['Беляш', 'Михаил', 'Чарли'], favoriteToy: { name: 'мячик', size: 'маленький', }, }
Или даже функция:
const cat = { name: 'Том', meow: function () { console.log('мяу мяу') },}cat.meow()// мяу мяу
const cat = { name: 'Том', meow: function () { console.log('мяу мяу') }, } cat.meow() // мяу мяу
Свойства можно добавлять и после создания объекта:
const cat = {}cat.name = 'Simon'cat.gender = 'male'cat.color = 'brown'cat.age = 2cat.adorable = trueconsole.log(cat)// {// name: 'Simon',// gender: 'male',// color: 'brown',// age: 2,// adorable: true// }
const cat = {} cat.name = 'Simon' cat.gender = 'male' cat.color = 'brown' cat.age = 2 cat.adorable = true console.log(cat) // { // name: 'Simon', // gender: 'male', // color: 'brown', // age: 2, // adorable: true // }
Создать объект также можно с помощью конструктора Object
. Это объектно-ориентированный стиль программирования:
const book = new Object({ title: 'Война и мир', author: 'Лев Толстой' })
const book = new Object({ title: 'Война и мир', author: 'Лев Толстой' })
Объекты, созданные через фигурные скобки и через new
совершенно идентичны.
Чтение свойств
СкопированоСуществует два вида синтаксиса для обращения к значению свойства объекта, в обоих случаях используется имя свойства.
Самый распространённый способ — с помощью точки:
console.log(`На полке стоит «${book.title}»`)// На полке стоит «Война и мир»const pagesPerDay = book.pages / 365console.log(`Чтобы прочитать её за год, читайте ${pagesPerDay.toFixed(1)} страницы в день`)// Чтобы прочитать её за год, читайте 3.5 страницы в день
console.log(`На полке стоит «${book.title}»`) // На полке стоит «Война и мир» const pagesPerDay = book.pages / 365 console.log(`Чтобы прочитать её за год, читайте ${pagesPerDay.toFixed(1)} страницы в день`) // Чтобы прочитать её за год, читайте 3.5 страницы в день
Альтернативно для чтения можно использовать квадратные скобки:
console.log(`На полке стоит «${book['title']}»`)const pagesPerDay = book['pages'] / 365console.log(`Чтобы прочитать её за год, читайте ${pagesPerDay.toFixed(1)} страницы в день`)
console.log(`На полке стоит «${book['title']}»`) const pagesPerDay = book['pages'] / 365 console.log(`Чтобы прочитать её за год, читайте ${pagesPerDay.toFixed(1)} страницы в день`)
Если прочитать свойство, которого нет у объекта, то вернётся undefined
:
const signature = book.signatureconsole.log(signature)// undefined
const signature = book.signature console.log(signature) // undefined
Добавление и изменение свойств
СкопированоСозданный объект можно изменять — добавлять, изменять и удалять свойства.
Для добавления и изменения свойств используется одинаковый синтаксис. Нужно обратиться к свойству и присвоить в него значение с помощью стандартного оператора присваивания =
. Если свойство не существует, оно будет создано:
const book = { title: 'Капитанская дочка'}// добавляем новое свойствоbook.author = 'А.С.Пушкин'// изменяем существующееbook.title = 'Сказка о царе Салтане'console.log(book)// { title: 'Сказка о царе Салтане', author: 'А.С.Пушкин'}
const book = { title: 'Капитанская дочка' } // добавляем новое свойство book.author = 'А.С.Пушкин' // изменяем существующее book.title = 'Сказка о царе Салтане' console.log(book) // { title: 'Сказка о царе Салтане', author: 'А.С.Пушкин'}
Синтаксис с квадратными скобками работает и здесь:
const book = { title: 'Капитанская дочка'}// добавляем новое свойствоbook['author'] = 'А.С.Пушкин'// изменяем существующееbook['title'] = 'Сказка о царе Салтане'console.log(book)// { title: 'Сказка о царе Салтане', author: 'А.С.Пушкин'}
const book = { title: 'Капитанская дочка' } // добавляем новое свойство book['author'] = 'А.С.Пушкин' // изменяем существующее book['title'] = 'Сказка о царе Салтане' console.log(book) // { title: 'Сказка о царе Салтане', author: 'А.С.Пушкин'}
Удаление свойств
СкопированоДля удаления свойств используют оператор delete
:
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true, usersReading: [1946, 1293, 7743]}delete book.usersReadingdelete book['isFinished']console.log(book)// { title: 'Война и мир', author: 'Лев Толстой', pages: 1274 }
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true, usersReading: [1946, 1293, 7743] } delete book.usersReading delete book['isFinished'] console.log(book) // { title: 'Война и мир', author: 'Лев Толстой', pages: 1274 }
Чаще всего свойства не удаляют, а сбрасывают значение, устанавливая undefined
или подходящее по смыслу:
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true, usersReading: [1946, 1293, 7743]}book.usersReading = undefinedbook['isFinished'] = undefined// {// title: 'Война и мир',// author: 'Лев Толстой',// pages: 1274// isFinished: undefined,// usersReading: undefined// }
const book = { title: 'Война и мир', author: 'Лев Толстой', pages: 1274, isFinished: true, usersReading: [1946, 1293, 7743] } book.usersReading = undefined book['isFinished'] = undefined // { // title: 'Война и мир', // author: 'Лев Толстой', // pages: 1274 // isFinished: undefined, // usersReading: undefined // }
Имена свойств
СкопированоИмена свойств (иногда их называют ключи, или поля) могут быть либо строками, либо символами. Если использовать в качестве ключа другой тип данных, то он будет приведён к строке с помощью вызова метода to
:
const obj = {}const key = {}obj[key] = 'value for the object key'console.log(obj)// { '[object Object]': 'value for the object key' }
const obj = {} const key = {} obj[key] = 'value for the object key' console.log(obj) // { '[object Object]': 'value for the object key' }
Если ключ содержит пробел, то обращаться к нему возможно только через синтаксис квадратных скобок:
const obj = { 'the answer': 42}console.log(obj['the answer'])// 42
const obj = { 'the answer': 42 } console.log(obj['the answer']) // 42
Сравнение объектов
СкопированоОбъекты — ссылочный тип данных. Сравнению по ссылке посвящена отдельная статья.
При сравнении двух объектов JavaScript сравнивает не значения свойств этих объектов, а адреса в памяти, по которым эти объекты хранятся. Поэтому любое сравнение двух объектов будет возвращать false
, даже если они выглядят одинаково:
// создаётся один объектconst book = { title: 'Дюна' }// создаётся другой объектconst anotherBook = { title: 'Дюна' }console.log(book === anotherBook)// false
// создаётся один объект const book = { title: 'Дюна' } // создаётся другой объект const anotherBook = { title: 'Дюна' } console.log(book === anotherBook) // false
Сравнение будет возвращать true
, только если мы сравниваем переменные, указывающие на один и тот же объект:
// создаётся один объектconst book = { title: 'Дюна' }// в anotherBook записывается ссылка на объектconst anotherBook = bookconsole.log(book === anotherBook)// true
// создаётся один объект const book = { title: 'Дюна' } // в anotherBook записывается ссылка на объект const anotherBook = book console.log(book === anotherBook) // true
На практике
Скопированосоветует Скопировано
🛠 Современные версии JavaScript содержат много упрощений синтаксиса.
Например, методы объявлять по-старому:
const cat = { name: 'Том', meow: function () { console.log('мяу мяу') },}
const cat = { name: 'Том', meow: function () { console.log('мяу мяу') }, }
А можно использовать короткий синтаксис:
const cat = { name: 'Том', meow() { console.log('мяу мяу') },}
const cat = { name: 'Том', meow() { console.log('мяу мяу') }, }
Если у вас есть переменная со значением, и вы хотите создать свойство с тем же именем, то вместо старого подхода:
const firstName = 'Иван'const username = 'Killer3000'const user = { firstName: firstName, username: username}console.log(user)// { firstName: 'Иван', username: 'Killer3000' }
const firstName = 'Иван' const username = 'Killer3000' const user = { firstName: firstName, username: username } console.log(user) // { firstName: 'Иван', username: 'Killer3000' }
Можно сократить запись:
const firstName = 'Иван'const username = 'Killer3000'const user = { firstName, username}console.log(user)// { firstName: 'Иван', username: 'Killer3000' }
const firstName = 'Иван' const username = 'Killer3000' const user = { firstName, username } console.log(user) // { firstName: 'Иван', username: 'Killer3000' }
🛠 Если название свойства хранится в переменной, его значение можно прочитать через синтаксис квадратных скобок:
const user = { firstName: 'Марина', username: 'zloyDuh'}const prop = 'firstName'console.log(user[prop])// Марина
const user = { firstName: 'Марина', username: 'zloyDuh' } const prop = 'firstName' console.log(user[prop]) // Марина
🛠 Для проверки, есть ли свойство у объекта, используйте оператор in
:
const user = { firstName: 'Марина', username: 'zloyDuh'}console.log('firstName' in user)// trueconsole.log('age' in user)// false
const user = { firstName: 'Марина', username: 'zloyDuh' } console.log('firstName' in user) // true console.log('age' in user) // false
🛠 Чтобы обойти все ключи объекта, используют цикл for
🛠 Для копирования объектов используется спред-синтаксис:
const user = { firstName: 'Марина', username: 'zloyDuh'}const copy = { ...user }console.log(copy)// { firstName: 'Марина', username: 'zloyDuh'}
const user = { firstName: 'Марина', username: 'zloyDuh' } const copy = { ...user } console.log(copy) // { firstName: 'Марина', username: 'zloyDuh'}
При этом происходит поверхностное копирование — полностью копируются только свойства первого уровня вложенности. Подробнее об этом читайте статью «Поверхностное и глубокое копирование».
На собеседовании
Скопировано отвечает
СкопированоЧто проверяют:
Это часто встречающаяся группа вопросов на собеседовании. Отличить её можно по таким признакам: вам предлагают два и более JS-объекта, в которых программно меняют свойства по ключам. Спрашивают, что в результате попадёт в консоль при вызове какого-то определённого ключа.
Так проверяют ваше знание того, что значения объектов передаются по ссылке и что ключи в объекте — это способ построить связь с конкретными данными.
Ответ:
Обычно перед вами будет пример, вроде такого:
let cat = { name: 'Tom', isHunter: true}let mouse = { name: 'Jerry', isHunter: false}mouse = cat;cat.isHunter = false;mouse.isHunter = undefined;console.log(mouse.isHunter);
let cat = { name: 'Tom', isHunter: true } let mouse = { name: 'Jerry', isHunter: false } mouse = cat; cat.isHunter = false; mouse.isHunter = undefined; console.log(mouse.isHunter);
Разберёмся, как выполняется этот код.
- В начале переменные
mouse
иcat
указывают на собственные объекты. - В строке
mouse
мы присваиваем переменной mouse ссылку на объект cat. Можно рассматривать это как "связывание" переменных. Теперь обе переменные указывают на один и тот же объект= cat { name
.: ' Tom' , is Hunter : true} - Теперь
mouse
и. name cat
будут менять значения свойства одного и того же объекта.. name - Последнее изменение в этом объекте происходит присваиванием значения
undefined
ключуis
.Hunter - Выводя в консоль значение ключа
is
, получим последнее его обновление —Hunter undefined
.
Такой способ рассуждения классно описан в книге "Just JavaScript" Дэна Абрамова. Он предлагает метафору, где имена переменных связываются проводами с данными в них, а ключи в объектах представляются как провода с подписями. Когда вы меняете значения в объектах или переназначаете связи объектов и переменных, вы просто переключаете провода из одного штекера в другой.
let cat
mouse
Такие же рассуждения подходят и для более сложных случаев:
let cat = { name: 'Tom', isHunter: true}let mouse = { name: 'Jerry', isHunter: false}cat.isHunter = mouse.isHunter;mouse.isHunter = undefined;mouse = cat;console.log(mouse.isHunter);
let cat = { name: 'Tom', isHunter: true } let mouse = { name: 'Jerry', isHunter: false } cat.isHunter = mouse.isHunter; mouse.isHunter = undefined; mouse = cat; console.log(mouse.isHunter);
В этом примере в консоли будет false
, ведь данные в объекте, который выводится в консоль, изменены только однажды в строке cat
. После переменная mouse
была «подключена» к тому же объекту, на который указывает переменная cat
.
отвечает
СкопированоВ первом случае просто была вызвана функция, которая ничего не возвращает. Значение переменной будет равно undefined
const animal = Animal() // ❌console.log(animal) // undefined
const animal = Animal() // ❌ console.log(animal) // undefined
Во втором случае перед функцией Animal
стоит оператор new
. Функция Animal
становится конструктором. Она выполняется, но так как this
внутри функции не используется, и сама функция ничего не возвращает, то ничего не происходит. Результатом операции становится новый объект, который ссылается на функцию Animal
как на конструктор. Этот объект присваивается переменной animal
const animal = new Animal() // ✅
const animal = new Animal() // ✅
Если Animal
имеет вид:
function Animal() { this.name = 'Cat'}
function Animal() { this.name = 'Cat' }
То переменная animal
, созданная с помощью new
, будет иметь доступ к полю name
:
console.log(animal)// Animal { name: 'Cat' }// Если мы явно не возвращаем ничего из конструктора,// то получаем сам объект в качестве результата.
console.log(animal) // Animal { name: 'Cat' } // Если мы явно не возвращаем ничего из конструктора, // то получаем сам объект в качестве результата.
Рассмотрим возврат значения из конструктора
СкопированоОбычно в функции-конструкторе не используется оператор return
. Если return
используется срабатывают два правила:
- При вызове
return
с объектом, вместоthis
вернётся этот объект. - При вызове
return
с пустым или с примитивным значением, оно будет проигнорировано.
return
с объектом возвращает этот объект, во всех остальных случаях возвращается this
function Animal() { this.foo = 'BARBARBAR' return { foo: 'bar' // ⬅️ возвращает этот объект }}const animal = new Animal()console.log(animal.foo)// Вернет `bar`
function Animal() { this.foo = 'BARBARBAR' return { foo: 'bar' // ⬅️ возвращает этот объект } } const animal = new Animal() console.log(animal.foo) // Вернет `bar`
А вот пример с примитивом после return
:
function Animal() { this.foo = 'BARBARBAR' return 'bar' // ⬅️ возвращает this}const animal = new Animal()console.log(animal.foo)// Вернет BARBARBAR
function Animal() { this.foo = 'BARBARBAR' return 'bar' // ⬅️ возвращает this } const animal = new Animal() console.log(animal.foo) // Вернет BARBARBAR
отвечает
СкопированоОбъект первого класса (first class object или first class citizen) это объект, который может быть передан как аргумент функции, возвращён из функции или присвоен переменной.
Функции в JavaScript полностью соответствуют этому определению.
Функцию можно присвоить переменной:
const multipleTwo = (n) => n * 2;
const multipleTwo = (n) => n * 2;
Функция может быть передаваемым аргументом другой функции:
async function loadData(func) { loading = true; // другой код относящийся к инициализации статусов загрузки await func(); loading = false; // другой код относящийся к обработке статуса загрузки}function getData() { // код получения данных с сервера}loadData(getData);
async function loadData(func) { loading = true; // другой код относящийся к инициализации статусов загрузки await func(); loading = false; // другой код относящийся к обработке статуса загрузки } function getData() { // код получения данных с сервера } loadData(getData);
Функции могут быть возвращаемым значением другой функции:
function makeAdder(x) { return function(y) { return x + y; };};
function makeAdder(x) { return function(y) { return x + y; }; };