Объект

Непримитивный тип данных. Представляет собой набор свойств.

Время чтения: 6 мин

Кратко

Скопировано

Кроме примитивных типов в 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 Object() совершенно идентичны.

Чтение свойств

Скопировано

Существует два вида синтаксиса для обращения к значению свойства объекта, в обоих случаях используется имя свойства.

Самый распространённый способ — с помощью точки:

        
          
          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
// }

        
        
          
        
      

Имена свойств

Скопировано

Имена свойств (иногда их называют ключи, или поля) могут быть либо строками, либо символами. Если использовать в качестве ключа другой тип данных, то он будет приведён к строке с помощью вызова метода toString():

        
          
          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...in

🛠 Для копирования объектов используется спред-синтаксис:

        
          
          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);

        
        
          
        
      

Разберёмся, как выполняется этот код.

  1. В начале переменные mouse и cat указывают на собственные объекты.
  2. В строке mouse = cat мы присваиваем переменной mouse ссылку на объект cat. Можно рассматривать это как "связывание" переменных. Теперь обе переменные указывают на один и тот же объект { name: 'Tom', isHunter: true}.
  3. Теперь mouse.name и cat.name будут менять значения свойства одного и того же объекта.
  4. Последнее изменение в этом объекте происходит присваиванием значения undefined ключу isHunter.
  5. Выводя в консоль значение ключа isHunter, получим последнее его обновление — undefined.

Такой способ рассуждения классно описан в книге "Just JavaScript" Дэна Абрамова. Он предлагает метафору, где имена переменных связываются проводами с данными в них, а ключи в объектах представляются как провода с подписями. Когда вы меняете значения в объектах или переназначаете связи объектов и переменных, вы просто переключаете провода из одного штекера в другой.

let cat = { name: 'Tom', isHunter: true}

Схема. Объект cat имеет свойство name со значением Tom и свойство isHunter со значением true

mouse = cat

Схема. В объект mouse присваивается объект cat со всеми свойствами и значениями

Такие же рассуждения подходят и для более сложных случаев:

        
          
          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.isHunter = mouse.isHunter. После переменная 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 используется срабатывают два правила:

  1. При вызове return с объектом, вместо this вернётся этот объект.
  2. При вызове 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;
  };
};