Об'єктний ініціалізатор
Об'єктний ініціалізатор – це розділений список з нуля або більше пар назв властивостей та відповідних їм значень в об'єкті, оточений фігурними дужками ({}
). Також об'єкти можуть бути ініціалізовані за допомогою Object.create()
або шляхом виклику функції-конструктора з оператором new
.
Спробуйте його в дії
Синтаксис
o = {
a: "foo",
b: 42,
c: {},
1: "числова літеральна властивість",
"foo:bar": "рядкова літеральна властивість",
shorthandProperty,
method(parameters) {
// …
},
get property() {},
set property(value) {},
[expression]: "обчислена властивість",
__proto__: prototype,
...spreadProperty,
};
Опис
Об'єктний ініціалізатор – це вираз, що описує ініціалізацію об'єкта
. Об'єкти складаються з _властивостей, що використовуються для опису об'єкта. Значення властивостей об'єкта можуть містити як примітивні типи даних, так і інші об'єкти.
Запис літералів об'єктів і JSON
Запис літералів об'єктів – це не те саме, що JavaScript Object Notation (JSON – об'єктний запис JavaScript). Хоч вони мають подібний вигляд, між ними є різниця:
- JSON дозволяє оголошення властивостей лише за допомогою запису
"property": value
. Назва властивостей повинна бути в подвійних лапках, і таке оголошення не може бути скороченим. Також не дозволені обчислені назви властивостей. - Значення властивостей об'єктів JSON можуть бути рядками, числами,
true
,false
,null
, масивами або іншими об'єктами JSON. Це означає, що JSON не може виражати методи або не звичайні об'єкти, як тоDate
orRegExp
. - У JSON
"__proto__"
є звичайним ключем властивості. В об'єктному літералі такий ключ задає прототип об'єкта.
JSON – це сувора підмножина запису літералів об'єктів, тобто будь-який дійсний текст JSON може бути розібраний як літерал об'єкта і, ймовірно, не призведе до жодних синтаксичних помилок. Єдиним винятком є те, що запис літерала об'єкта не дозволяє дублювання ключів __proto__
, що відрізняється від поведінки JSON.parse()
. Цей статичний метод розглядає __proto__
як звичайну властивість і бере за її значення останнє входження. Єдиний випадок, коли об'єктні значення, котрі вони представляють (тобто їхня семантика), відрізняються, також стосується ключа __proto__
: в літералах об'єктів цей ключ задає прототип об'єкта, а для JSON це звичайна властивість.
console.log(JSON.parse('{ "__proto__": 0, "__proto__": 1 }')); // {__proto__: 1}
console.log({ "__proto__": 0, "__proto__": 1 }); // SyntaxError: Duplicate __proto__ fields are not allowed in object literals
console.log(JSON.parse('{ "__proto__": {} }')); // { __proto__: {} }
console.log({ "__proto__": {} }); // {} (with {} as prototype)
Приклади
Створення об'єктів
Порожній об'єкт без властивостей може бути створений так:
const object = {};
Проте перевагою запису літерала або ініціалізатора є те, що можна швидко створювати об'єкти зі властивостями всередині фігурних дужок. Записується низка пар key: value
, розділених комами.
Наступний код створює об'єкт з трьома властивостями, чиї ключі – "foo"
, "age"
і "baz"
. Значення цих ключів – рядок "bar"
, число 42
і ще один об'єкт.
const object = {
foo: "bar",
age: 42,
baz: { myProp: 12 },
};
Звертання до властивостей
Коли створено об'єкт, може знадобитися зчитати або змінити його. До його властивостей можна звернутися за допомогою запису крапки або запису квадратних дужок. (Докладніше про це читайте в аксесорах властивостей.)
object.foo; // "bar"
object["age"]; // 42
object.baz; // {myProp: 12}
object.baz.myProp; //12
Оголошення властивостей
Ми вже навчилися записувати властивості за допомогою запису ініціалізатора. Нерідко у коді є змінні, котрі хочеться додати в об'єкт. Можна зустріти такий код:
const a = "foo";
const b = 42;
const c = {};
const o = {
a: a,
b: b,
c: c,
};
Є коротший запис, що дає змогу досягнути такого ж результату:
const a = "foo";
const b = 42;
const c = {};
// Властивості з назвами-скороченнями
const o = { a, b, c };
// Інакше кажучи,
console.log(o.a === { a }.a); // true
Дублювання назв властивостей
Коли в записі об'єктного ініціалізатора є дві властивості з однаковою назвою, друга з них відкидає першу.
const a = { x: 1, x: 2 };
console.log(a); // {x: 2}
Починаючи від ES2015 дублювання назв властивостей дозволено всюди, в тому числі в суворому режимі. Також дублікати назв властивостей можуть зустрічатися у класах. Єдиний виняток – приватні властивості: вони повинні бути унікальні в межах тіла класу.
Оголошення методів
Властивість об'єкта також може вказувати на функцію або метод-гетер чи метод-сетер.
const o = {
property: function (parameters) {},
get property() {},
set property(value) {},
};
Доступний скорочений запис, тож ключове слово function
уже не потрібне.
// Скорочені назви властивостей
const o = {
property(parameters) {},
};
Також є спосіб стисло оголошувати методи-генератори.
const o = {
*generator() {
// …
},
};
Що рівносильно цьому записові у стилі ES5 (утім, зверніть увагу на те, що ECMAScript 5 не має генераторів):
const o = {
generator: function* () {
// …
},
};
Більше інформації та прикладів з методами – в оголошенні методів.
Обчислені назви властивостей
Запис об'єктного ініціалізатора також підтримує обчислені назви властивостей. Це дає змогу додавати вираз у квадратних дужках []
, котрий буде обчислений і вжитий як назва властивості. Це нагадує запис квадратних дужок запису аксесора властивостей, котрий ви уже, можливо, використовуєте для зчитування та запису властивостей.
Відтак, можна використовувати подібний запис і в об'єктних літералах:
// Обчислені назви властивостей
let i = 0;
const a = {
[`foo${++i}`]: i,
[`foo${++i}`]: i,
[`foo${++i}`]: i,
};
console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3
const items = ["A", "B", "C"];
const obj = {
[items]: "Привіт",
};
console.log(obj); // A,B,C: "Привіт"
console.log(obj["A,B,C"]); // "Привіт"
const param = "size";
const config = {
[param]: 12,
[`mobile${param.charAt(0).toUpperCase()}${param.slice(1)}`]: 4,
};
console.log(config); // {size: 12, mobileSize: 4}
Розгортання властивостей
Літерали об'єктів підтримують запис розгортання. Він копіює власні перелічувані властивості з даного об'єкта в новий об'єкт.
Відтак, поверхневе клонування (окрім prototype
) і злиття об'єктів тепер можливо за допомогою коротшого запису, ніж Object.assign()
.
const obj1 = { foo: "bar", x: 42 };
const obj2 = { foo: "baz", y: 13 };
const clonedObj = { ...obj1 };
// { foo: "bar", x: 42 }
const mergedObj = { ...obj1, ...obj2 };
// { foo: "baz", x: 42, y: 13 }
Застереження: Зверніть увагу на те, що
Object.assign()
запускає сетери, а запис розгортання – ні!
Сетер прототипа
Означення властивості в формі __proto__: value
або "__proto__": value
не створює властивості з назвою __proto__
. Натомість якщо задане значення є об'єктом або null
, то така властивість спрямовує [[Prototype]]
створеного об'єкта на це значення. (Якщо значення не є об'єктом або null
, то об'єкт не змінюється).
Зверніть увагу на те, що ключ __proto__
– це стандартизований запис, на противагу нестандартним і повільним аксесорам Object.prototype.__proto__
. Він задає [[Prototype]]
під час створення об'єкта, подібно до Object.create
— а не змінює ланцюжок прототипів.
const obj1 = {};
console.log(Object.getPrototypeOf(obj1) === Object.prototype); // true
const obj2 = { __proto__: null };
console.log(Object.getPrototypeOf(obj2)); // null
const protoObj = {};
const obj3 = { "__proto__": protoObj };
console.log(Object.getPrototypeOf(obj3) === protoObj); // true
const obj4 = { __proto__: "не об'єкт і не null" };
console.log(Object.getPrototypeOf(obj4) === Object.prototype); // true
console.log(Object.hasOwn(obj4, "__proto__")); // false
В літералі об'єкта дозволений лише один сетер прототипа. Кілька сетерів прототипа разом – це синтаксична помилка.
Означення властивостей, що не використовують запис "двокрапки", не є сетерами прототипу. Це означення властивостей, що поводяться ідентично до аналогічних означень з будь-якою іншою назвою.
const __proto__ = "змінна";
const obj1 = { __proto__ };
console.log(Object.getPrototypeOf(obj1) === Object.prototype); // true
console.log(Object.hasOwn(obj1, "__proto__")); // true
console.log(obj1.__proto__); // "змінна"
const obj2 = { __proto__() { return "привіт"; } };
console.log(obj2.__proto__()); // "привіт"
const obj3 = { ["__proto__"]: 17 };
console.log(obj3.__proto__); // 17
// Змішування сетера прототипу зі звичайними властивостями з ключем "__proto__"
const obj4 = { ["__proto__"]: 17, __proto__: {} }; // {__proto__: 17} (з {} як прототипом)
const obj5 = {
["__proto__"]: 17,
__proto__: {},
__proto__: null, // SyntaxError: Duplicate __proto__ fields are not allowed in object literals
};
const obj6 = {
["__proto__"]: 17,
["__proto__"]: "привіт",
__proto__: null,
}; // {__proto__: "привіт"} (з null як прототипом)
const obj7 = {
["__proto__"]: 17,
__proto__,
__proto__: null,
}; // {__proto__: "variable"} (з null як прототипом)
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Object initializer
|
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1 | Internet Explorer Full support 1 | Opera Full support 4 | Safari Full support 1 | WebView Android Full support 1 | Chrome Android Full support 18 | Firefox for Android Full support 4 | Opera Android Full support 10.1 | Safari on iOS Full support 1 | Samsung Internet Full support 1.0 | Deno Full support 1.0 | Node.js Full support 0.10.0 |
Computed property names
|
Chrome Full support 47 | Edge Full support 12 | Firefox Full support 34 | Internet Explorer No support Ні | Opera Full support 34 | Safari Full support 8 | WebView Android Full support 47 | Chrome Android Full support 47 | Firefox for Android Full support 34 | Opera Android Full support 34 | Safari on iOS Full support 8 | Samsung Internet Full support 5.0 | Deno Full support ?null | Node.js Full support 4.0.0 |
Shorthand method names
|
Chrome Full support 47 | Edge Full support 12 | Firefox Full support 34 | Internet Explorer No support Ні | Opera Full support 34 | Safari Full support 9 | WebView Android Full support 47 | Chrome Android Full support 47 | Firefox for Android Full support 34 | Opera Android Full support 34 | Safari on iOS Full support 9 | Samsung Internet Full support 5.0 | Deno Full support ?null | Node.js Full support 4.0.0 |
Shorthand property names
|
Chrome Full support 47 | Edge Full support 12 | Firefox Full support 33 | Internet Explorer No support Ні | Opera Full support 34 | Safari Full support 9 | WebView Android Full support 47 | Chrome Android Full support 47 | Firefox for Android Full support 33 | Opera Android Full support 34 | Safari on iOS Full support 9 | Samsung Internet Full support 5.0 | Deno Full support ?null | Node.js Full support 4.0.0 |
Spread properties
|
Chrome Full support 60 | Edge Full support 79 | Firefox Full support 55 | Internet Explorer No support Ні | Opera Full support 47 | Safari Full support 11.1 | WebView Android Full support 60 | Chrome Android Full support 60 | Firefox for Android Full support 55 | Opera Android Full support 44 | Safari on iOS Full support 11.3 | Samsung Internet Full support 8.0 | Deno Full support ?null | Node.js Full support 8.3.0 |