Object.create()

Статичний метод Object.create() ("створити") створює новий об'єкт, використовуючи певний наявний об'єкт як прототип новоствореного об'єкта.

Спробуйте його в дії

Синтаксис

Object.create(proto)
Object.create(proto, propertiesObject)

Параметри

proto

Об'єкт, який буде прототипом новоствореного об'єкта.

propertiesObject Необов'язкове

Якщо цей параметр вказано, і він не дорівнює undefined, — то це має бути об'єкт, чиї власні перелічувані властивості позначають дескриптори властивостей, які, з відповідними іменами, буде додано до новоствореного об'єкта. Формат цих властивостей відповідає другому аргументові методу Object.defineProperties().

Повернене значення

Новий об'єкт, зі вказаними властивостями й прототипним об'єктом.

Винятки

TypeError

Викидається в разі, якщо proto не дорівнює null, і не є об'єктом.

Приклади

Реалізація класичного успадкування за допомогою Object.create()

Нижче наведено приклад того, як можна використати Object.create() для реалізації класичного успадкування. Результатом є одинарна (проста) форма успадкування — це все, що підтримується в JavaScript.

// Shape - надклас
function Shape() {
  this.x = 0;
  this.y = 0;
}

// метод надкласу
Shape.prototype.move = function (x, y) {
  this.x += x;
  this.y += y;
  console.info("Фігуру переміщено.");
};

// Rectangle - підклас
function Rectangle() {
  Shape.call(this); // викликати конструктор надкласу.
}

// підклас розширює надклас
Rectangle.prototype = Object.create(Shape.prototype, {
  // Якщо не встановити Rectangle значенням властивості Rectangle.prototype.constructor,
  // він візьме значення prototype.constructor від Shape (батьківського класу).
  // Аби уникнути цього, слід встановити Rectangle (дочірній клас) значенням prototype.constructor.
  constructor: {
    value: Rectangle,
    enumerable: false,
    writable: true,
    configurable: true,
  },
});

const rect = new Rectangle();

console.log(
  "Чи є `rect` примірником класу Rectangle?",
  rect instanceof Rectangle,
); // true
console.log("Чи є `rect` примірником класу Shape?", rect instanceof Shape); // true
rect.move(1, 1); // Друкує 'Фігуру переміщено.'

Слід зауважити, що є певні перестороги для застосування create(), які слід мати на увазі. Зокрема — повторне додавання властивості constructor для забезпечення вірної семантики. І хоча вважається, що Object.create() відпрацьовує швидше, аніж пряма заміна прототипу за допомогою Object.setPrototypeOf(), цією різницею насправді можна знехтувати в разі, якщо створення примірників не відбувається, та поки не оптимізовано доступ до властивостей. В сучасному коді, в будь-якому разі слід надавати перевагу синтаксису класів.

Застосування аргументу propertiesObject з Object.create()

Метод Object.create() дає можливість тонкого контролю над процесом створення об'єкта. Синтаксис об'єктного ініціалізатора насправді є синтаксичним цукром для Object.create(). За допомогою Object.create() можна створювати об'єкти з призначеним прототипом, і також з певними властивостями. Варто зауважити, що другий параметр ставить у відповідність ключам дескриптори властивості. Тобто також можна керувати перелічуваністю, налаштованістю та іншими характеристиками, що неможливо при застосуванні об'єктних ініціалізаторів.

o = {};
// ...що еквівалентно такому виразові:
o = Object.create(Object.prototype);

o = Object.create(Object.prototype, {
  // foo — це пересічна властивість з даними
  foo: {
    writable: true,
    configurable: true,
    value: "hello",
  },
  // bar — це властивість з аксесорами
  bar: {
    configurable: false,
    get() {
      return 10;
    },
    set(value) {
      console.log("Setting `o.bar` to", value);
    },
  },
});

// Створити новий об'єкт, чиїм протипом є новий порожній об'єкт,
// та додати до нього єдину властивість 'p' зі значенням 42.
o = Object.create({}, { p: { value: 42 } });

За допомогою Object.create() можна створити об'єкт, чиїм прототипом є null. Еквівалентним синтаксисом на об'єктних ініціалізаторах було б вказання ключа __proto__.

o = Object.create(null);
// ...що еквівалентно такому:
o = { __proto__: null };

Усталено властивості не є записуваними, перелічуваними чи налаштовними.

o.p = 24; // викидає виняток у суворому режимі
o.p; // 42

o.q = 12;
for (const prop in o) {
  console.log(prop);
}
// 'q'

delete o.p;
// повертає false; викидає виняток у суворому режимі

Необхідно явно вказувати writable, enumerable та configurable, аби означити властивість з такими само атрибутами, як при використанні ініціалізатора.

o2 = Object.create(
  {},
  {
    p: {
      value: 42,
      writable: true,
      enumerable: true,
      configurable: true,
    },
  },
);
// Це не еквівалентно виразові:
// o2 = Object.create({ p: 42 })
// який лише створить об'єкт із прототипом { p: 42 }

Object.create() можна використовувати для імітації поведінки оператора new.

function Constructor() {}
o = new Constructor();
// ...що еквівалентно такому:
o = Object.create(Constructor.prototype);

Авжеж, якщо функція Constructor містить якийсь код ініціалізації — метод Object.create() не зможе його відтворити.

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
create
Chrome Full support 5
Edge Full support 12
Firefox Full support 4
Internet Explorer Full support 9
Opera Full support 11.6
Safari Full support 5
WebView Android Full support 1
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 12
Safari on iOS Full support 5
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0

Дивіться також