Главная » Объекты и новый синтаксис объектных литералов (ES6)

Объекты и новый синтаксис объектных литералов (ES6)


08.03.2021, 21:53
Введение в объекты

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

Имена свойств обычно являются строками (могут также быть значениями Symbol).
Объект может содержать в себе множество значений (как элементарных, так и составных, например, тех же объектов) и позволяет хранить и извлекать внутренние значения по имени.

Кроме собственных свойств объект JavaScript наследует свойства другого объекта, своего прототипа.

Объекты изменяемы и обрабатываются по ссылке, а не по значению.

Если переменная x ссылается на объект и есть код:

Код

let y = x;

То в переменной y будет сохранена ссылка на тот же объект, а не его копию. Поэтому, любые изменения, вносимые в объект через переменную y, будут видны и в переменной x.

Свойство объекта

Именем свойства объекта может быть любая строка, включая пустую. Объект не может иметь два свойства с одинаковым именем.

Свойства, не унаследованные объектом от объекта прототипа, являются его собственными свойствами.

Каждое свойство, помимо имени и значения, имеет три атрибута:

- writable (допускает запись) указывает, можно ли устанавливать значение свойства;

- enumerable (допускает перечисление) указывает, возвращается ли имя свойства в цикле for/in;

- configurable (допускает конфигурирование) указывает, можно ли удалять свойство и изменять его атрибуты.

По умолчанию все свойства создаваемых вами объектов допускают запись, перечисление и конфигурирование.

Создание объектов

Создать объект можно тремя способами:

- с помощью объектных литералов

- с помощью ключевого слова new

- с помощью функции Object.create()

Объектный литерал - это выражение, создающее и инициализирующее новый отдельный объект каждый раз, когда оно вычисляется. При каждом вычислении литерала вычисляется значение каждого его свойства.

Один литерал может создать много новых объектов, значения свойств которых могут отличаться друг от друга (например, если объектный литерал находится внутри тела цикла или в неоднократно вызываемой функции).

Базовый синтаксис объектного литерала: список пар имя: значение, разделённых запятыми, заключённый в фигурные скобки:

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  }
};

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

Создание объектов с помощью операции new

Оператор new создаёт и инициализирует новый объект.

Для инициализации вновь созданного объекта используется функция-конструктор. Имя функции при этом пишется с заглавной буквы, например:

Код

let a = new Object(); /* Создание пустого объекта, аналог { } */

let b = new Array(); /* Создание пустого массива, аналог [ ] */

let c = new Date(); /* Создание объекта Date, представление текущего времени */

let d = new Map(); // Создание объекта Map для отображения ключ/значение

Удалить свойство объекта можно, используя оператор delete

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  }
  };

  delete userProfile.age;

  console.log(userProfile);

В консоли видим, что свойство age удалено из объекта:

{ name: 'Alex', armor: { ammunition: 100, 'first aid': true } }

Перебрать свойства объекта

С помощью цикла for/of перебрать объект нельзя

можно с помощью цикла for/in , напоминаю синтаксис:

Код

for (переменная in объект) {
  оператор
}

перебираем свойства нашего объекта userProfile:

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  }
};

for (let key in userProfile) {
  console.log(`Свойство ${key} имеет значение ${userProfile[key]}`);
}

здесь key каждый раз при проходе цикла будет изменять своё значение (name, age, armor), цикл повторится столько раз, сколько свойств содержится в объекте.

В консоли результат перебора свойств объекта:

Свойство name имеет значение Alex
Свойство age имеет значение 30
Свойство armor имеет значение [object Object]

Значение свойства armor не вывелось напрямую, так как JavaScript не может вложенный объект вывести в виде строки, поэтому выводит такое строковое представление объекта [object Object].

Чтобы вывести свойства и вложенного объекта, применяем условие, проверяем на тип данных перебираемые свойства объекта userProfile, и если свойство является объектом, запускаем перебор свойств внутри него и вывод их в консоль, также как мы это сделали для объекта userProfile:

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  }
};

for (let key in userProfile) {
  if (typeof(userProfile[key]) === "object") {
  for (let i in userProfile[key]) {
  console.log(`Свойство ${i} имеет значение ${userProfile[key][i]}`);
  }
  } else {
  console.log(`Свойство ${key} имеет значение ${userProfile[key]}`);
  }  
}

Узнать количество свойств в объекте, можно с помощью метода Object.keys()

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  }
  };

console.log(Object.keys(userProfile));

в результате получаем массив с именами свойств объекта

[ 'name', 'age', 'armor' ]

Теперь, используя свойство length для массива, мы получим количество элементов массива, а значит и нашего объекта:

Код

console.log(Object.keys(userProfile).length); // => 3

Мы можем создать свой метод для нашего объекта, в качестве его значения используя функцию, назовём его finalMessage:

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  },
  finalMessage: function() {
  console.log("Victory! ");
  }
  };

теперь мы можем его запустить:

Код

let userProfile = {
  name: "Alex",
  age: 30,
  armor: {
  ammunition: 100,
  "first aid": true
  },
  finalMessage: function() {
  console.log("Victory! ");
  }
  };

userProfile.finalMessage(); // => Victory!

Деструктуризация объекта (ES6)

Допустим, есть объект, в числе свойств которого есть вложенный объект

Код

const obj = {
  a: 10,
  b: 5,
  c: {
  d: 12,
  e: 22
  }
};

При деструктуризации объекта мы "распаковываем" вложенный объект или массив в переменные, чтобы потом с ними можно было работать. В правой части указываем тот вложенный объект, который мы распаковываем, а в левой - список названий переменных.

Код

const {d, e} = obj.c;

выводим в консоль значения переменных d и e:

Код

console.log(d); /* => 12 */
console.log(e); // => 22

Если нужно свойство объекта присвоить переменной с другим названием, например, в нашем объекте userProfile есть свойство "first aid", присвоим его переменной firstAid.

Для этого просто используем двоеточие:

Код

const {ammunition, "first aid" : firstAid} = userProfile.armor;

выведем в консоль значение переменной firstAid:

Код

console.log(firstAid); // => true

Прототипы

Большинство объектов в JavaScript наследуют свойства от ассоциированного с ними другого объекта, прототипа.

Объекты, созданные объектными литералами, имеют в качестве объекта Object.prototype.

Объект, созданный с помощью new Object(), также наследует Object.prototype

Объект, созданный с помощью new Array(), использует в качестве прототипа Array.prototype.

Объект, созданный с помощью new Date(), получает прототип Date.prototype.

Большинство объектов в JavaScript имеют прототип, и только некоторые имеют свойство prototype,
именно они определяют прототипы для всех остальных объектов.

Object.prototype не имеет прототипа, не наследует никаких свойств

Большинство встроенных конструкторов (также как и созданных пользователем) имеют прототип, наследованный от Object.prototype.

Получается цепочка прототипов, например: Date.prototype наследует свойства от Object.prototype, при этом объект Date, созданный с помощью new Date(), унаследует свойства от Date.prototype и от Object.prototype.

Создание объектов с помощью Object.create()

Создаём новый объект:

Код

const persone = Object.create({}, {});

Метод create принимает в себя два параметра (оба объекты), первый из них - это объект, который будет прототипом вновь созданного объекта, второй описывает свойства нового объекта.

Свойства здесь задаются также в виде объекта, при этом используется ключ value:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex"
  }
});

Если сейчас вывести в консоли браузера содержимое объекта persone, то увидим ожидаемый результат

Код

console.log(persone); // => { name: "Alex" }

Добавим еще свойство в наш объект:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex"
  },
  birthYear: {
  value: 1994
  }
});

По умолчанию для этих свойств значение атрибута enumerable будет равным false, поэтому, если сейчас объект persone перебрать с помощью цикла for/in, то эти свойства цикл не вернёт, потому как именно значение параметра enumerable указывает, возвращается ли имя свойства в цикле for/in.

Поменяв значения атрибута enumerable на true, зададим перебор с помощью цикла for/in:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  }
});

for (let key in persone) {
  console.log('Key: ', key);
}

В консоли получим список свойств:


Key: name
Key: birthYear

Можно дополнительно получить сразу и их значения:

Код

for (let key in persone) {
  console.log('Key: ', key, persone[key]);
}

Key: name Alex
Key: birthYear 1994

Напрямую сейчас изменять значения свойств объекта также не получится, поскольку по умолчанию значение дескриптора writable также установлено в false (напоминание: - writable (допускает запись) указывает, можно ли устанавливать значение свойства)

Код

persone.name = "Jason"; // не сработает, если writable установлено false

Меняем значение для writable на true и теперь мы можем изменять значение свойства name:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  }
});

persone.name = "Jason";  

console.log(persone.name); // => Jason

Удалить какое-либо свойство можно будет после того, как будет установлено значение true для дескриптора configurable:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true,
  configurable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  }
});

delete persone.name;

console.log(persone); // => { birthYear: 1994 }

Геттеры и сеттеры

С помощью дескрипторов мы можем задавать свойства, работающие как функции. Для этого мы указываем функцию в get, геттер нам должен вернуть какое-то новое значение:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true,
  configurable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  },
  age: {
  get() {
  return 'Hello, World';  
  },
  set() {}
  }
});

console.log(persone.age); // => Hello, World

Так, например, можно вычислить возраст на основе имеющихся данных:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true,
  configurable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  },
  age: {
  get() {
  return new Date().getFullYear() - this.birthYear;
  },
  set() {}
  }
});

console.log(persone.age); // => 27

Для set можно прописать какое-то значение value и использовать его для вывода в консоль:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true,
  configurable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  },
  age: {
  get() {
  return new Date().getFullYear() - this.birthYear;
  },
  set(value) {
  console.log("Set age", value);
  }
  }
});

console.log(persone.age = 35); // => Set age 35

В геттерах и сеттерах можно реализовывать всевозможную логику, например, поменять цвет фона:

Код

const persone = Object.create({}, {
  name: {
  value: "Alex",
  enumerable: true,
  writable: true,
  configurable: true
  },
  birthYear: {
  value: 1994,
  enumerable: true
  },
  age: {
  get() {
  return new Date().getFullYear() - this.birthYear;
  },
  set(value) {
  document.body.style.background = 'red';
  }
  }
});

persone.age = 'Меняем цвет фона!'; // => фон страницы станет красным

КОММЕНТАРИИ (1)

В ES6/2015 появилась новая возможность для определения объекта, ключи которые имеют такие же имена, как и переменные, переданные в качестве свойств.

Например, есть переменные:

Код
let cat = 'Мурзик';
let dog = 'Шарик';


Объявляем объект:

Код
let myObj = {
     cat,
     dog
}


Проверяем, выводим содержимое объекта в консоль:

Код
console.log(myObj);


Код
{ cat: 'Мурзик', dog: 'Шарик' }