Learn JavaScript

Object.create() - метод для создания объекта с указанным прототипом в JavaScript

Object.create() создаёт новый объект с указанным прототипом.

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

Синтаксис

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

proto - объект, который станет прототипом нового объекта.

propertiesObject - необязательный объект с дескрипторами свойств.

Что делает Object.create()

Метод создаёт новый объект и сразу привязывает к нему указанный прототип.

const animal = {
  speak() {
    console.log("sound");
  },
};

const dog = Object.create(animal);

dog.speak(); // "sound"

У dog нет собственного метода speak, но он получает его через прототип.

Прототип нового объекта

Это самое важное в Object.create().

const animal = { type: "animal" };
const dog = Object.create(animal);

console.log(dog.type); // "animal"
console.log(Object.getPrototypeOf(dog) === animal); // true

То есть animal становится прототипом для dog.

Object.create() и обычный объект

Если передать обычный объект как прототип, новый объект будет наследоваться от него.

const base = { kind: "base" };
const obj = Object.create(base);

console.log(obj.kind); // "base"

Но важно помнить, что это не то же самое, что литерал {}:

const a = {};
const b = Object.create({});

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

Object.create(null)

Очень важный случай - создать объект вообще без прототипа.

const dict = Object.create(null);

console.log(Object.getPrototypeOf(dict)); // null

Такой объект:

  • не наследуется от Object.prototype
  • не имеет методов вроде toString()
  • часто используется как простое хранилище ключ-значение

Пример:

const dict = Object.create(null);

dict.name = "Anna";

console.log(dict.name); // "Anna"

Почему это может быть полезно

У обычного объекта есть наследуемые свойства и методы.

У объекта без прототипа их нет:

const normal = {};
const plain = Object.create(null);

console.log("toString" in normal); // true
console.log("toString" in plain);  // false

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

propertiesObject и дескрипторы

Вторым аргументом можно сразу описать свойства нового объекта.

const user = Object.create(Object.prototype, {
  name: {
    value: "Anna",
    writable: true,
    enumerable: true,
    configurable: true,
  },
});

console.log(user.name); // "Anna"

Это работает через дескрипторы свойств, как и Object.defineProperty().

Почему второй аргумент используют не так часто

Хотя возможность полезная, в обычном коде чаще пишут проще:

const user = Object.create(Object.prototype);
user.name = "Anna";

Или вообще используют литерал объекта:

const user = { name: "Anna" };

Поэтому второй аргумент чаще встречается в более специфичных случаях.

Object.create() и {}

Для обычного создания объекта литерал {} почти всегда проще:

const user = {};

Object.create() обычно выбирают тогда, когда:

  • важен конкретный прототип
  • нужен объект без прототипа
  • нужно явно работать через прототипное наследование

Object.create() и new Object()

new Object() создаёт обычный объект.

Object.create() позволяет точнее управлять его прототипом.

const a = new Object();
const b = Object.create(null);

console.log(Object.getPrototypeOf(a) === Object.prototype); // true
console.log(Object.getPrototypeOf(b)); // null

Поэтому это методы для разных задач.

Object.create() не копирует объект

Если передать объект как прототип, новый объект не станет его копией.

const animal = { type: "animal" };
const dog = Object.create(animal);

console.log(dog.type); // "animal"
console.log(dog.hasOwnProperty("type")); // false

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

Когда это полезно

Object.create() удобно использовать, когда:

  • нужно создать объект с конкретным прототипом
  • нужен объект без прототипа через Object.create(null)
  • вы работаете с прототипным наследованием напрямую

Пример:

const person = {
  greet() {
    console.log(`Привет, я ${this.name}`);
  },
};

const user = Object.create(person);
user.name = "Anna";

user.greet(); // "Привет, я Anna"

Частые ошибки

Думать, что Object.create(obj) делает копию

const base = { role: "admin" };
const user = Object.create(base);

console.log(user.role); // "admin"

Это не копия объекта base, а новый объект с base в прототипе.

Забывать, что у Object.create(null) нет методов Object.prototype

const dict = Object.create(null);

// dict.toString(); // Ошибка

Такой объект устроен специально проще.

Путать собственные и наследуемые свойства

const base = { value: 1 };
const obj = Object.create(base);

console.log(obj.value); // 1
console.log(obj.hasOwnProperty("value")); // false

Значение доступно, но оно пришло из прототипа.

Быстрая памятка

  • Object.create() создаёт объект с указанным прототипом
  • Object.create(null) создаёт объект без прототипа
  • второй аргумент позволяет задавать свойства через дескрипторы
  • метод не копирует переданный объект, а использует его как прототип
  • для обычного объекта чаще используют литерал {}

Коротко

Object.create() - это способ явно управлять прототипом нового объекта. Главное, что стоит запомнить: метод особенно полезен для объектов без прототипа и для случаев, где важно именно наследование, а не просто создание {}.