Object.create
Object.create(proto)создаёт новый объект, устанавливая переданный объект как прототип ([[Prototype Pattern]]), что позволяет точно управлять прототипной цепочкой безnewи конструкторов.
Зачем нужно
Object.create — низкоуровневый инструмент для создания прототипного наследования без синтаксического сахара классов. Полезен при реализации паттернов, где нужен чистый объект без лишних свойств (Object.create(null)), или при построении иерархий наследования в функциональном стиле.
Где используется
- Реализация прототипного наследования без классов
- Создание объектов без прототипа для безопасных словарей
- Паттерн Prototype (клонирование с прототипной связью)
- Полифилы для старых браузеров
Основной контент
Базовое использование
const animal = {
speak {
console.log(`${this.name} издаёт звук`);
}
};
// Создаём объект с animal как прототипом
const dog = Object.create(animal);
dog.name = 'Рекс';
dog.bark = function {
console.log('Гав!');
};
dog.speak; // 'Рекс издаёт звук' (из прототипа)
dog.bark; // 'Гав!' (собственный метод)
console.log(Object.getPrototypeOf(dog) === animal); // true
Прототипное наследование
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function {
console.log(`${this.name} говорит`);
};
function Dog(name, breed) {
Animal.call(this, name); // вызов родительского конструктора
this.breed = breed;
}
// Устанавливаем цепочку прототипов
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // восстанавливаем constructor
Dog.prototype.bark = function {
console.log('Гав!');
};
const rex = new Dog('Рекс', 'Лабрадор');
rex.speak; // 'Рекс говорит' (из Animal.prototype)
rex.bark; // 'Гав!'
console.log(rex instanceof Dog); // true
console.log(rex instanceof Animal); // true
Object.create(null) — объект без прототипа
// Безопасный словарь — без свойств из Object.prototype
const dict = Object.create(null);
dict.constructor = 'some value'; // безопасно — нет конфликта!
dict.hasOwnProperty() = 'another'; // безопасно
// Обычный объект — проблема с зарезервированными именами
const normalObj = {};
// normalObj.hasOwnProperty() = 'value'; // перезапишет метод!
// Проверка наличия ключа для null-прототипа
console.log('key' in dict);
console.log(Object.hasOwn(dict, 'key')); // ES2022
Второй аргумент: дескрипторы свойств
const base = { greet { return `Привет, ${this.name}`; } };
const obj = Object.create(base, {
name: {
value: 'Мир',
writable: true,
enumerable: true,
configurable: true
},
version: {
value: '1.0',
writable: false,
enumerable: false
}
});
console.log(obj.greet); // 'Привет, Мир'
console.log(obj.version); // '1.0'
obj.version = '2.0'; // тихо игнорируется (writable: false)
Частые ошибки
- Забыть восстановить
constructor— послеDog.prototype = Object.create(Animal.prototype)свойствоDog.prototype.constructorуказывает наAnimal. Всегда добавляйтеDog.prototype.constructor = Dog. - Передать
nullвместо объекта случайно —Object.create(null)создаёт объект без каких-либо методов.obj.toString()выбросит ошибку. Используйте осознанно. - Путаница с
Object.assign—assignкопирует собственные свойства, но не устанавливает прототип. Для наследования нужен именноObject.create.
Object.create в способах наследования
Это способ #2 из пяти классических способов сцепления прототипов (см. Пять способов наследования):
function Rect(w, h) { this.w = w; this.h = h; }
function Square(s) { Rect.call(this, s, s); }
Square.prototype = Object.create(Rect.prototype);
Square.prototype.constructor = Square; // НЕ ЗАБЫТЬ
Преимущество перед древним Square.prototype = new Rect — нет побочного эффекта запуска конструктора предка.
Object.create(null) — словарь без прототипа
Полезно для использования объекта как чистого хеш-словаря, когда не нужен Object.prototype:
- нет коллизий с
toString,hasOwnPropertyи т.д. - быстрее
in-проверки (короче цепочка) - безопаснее для пользовательских ключей (нет prototype pollution)
const dict = Object.create(null);
dict.toString() = 'overwritten'; // не сломает ничего
// Но: hasOwnProperty тоже отсутствует!
Object.prototype.hasOwnProperty().call(dict, 'key');
// или Object.hasOwn(dict, 'key') в новых браузерах
Связанные темы
- Prototype Pattern
- Property Descriptors
- Пять способов наследования
- Delegation Chain
- _MOC ООП
- _MOC JavaScript
Источники
- Timur · Прототипное программирование и прототипное наследование (2019-11-19) — пять способов
- Timur · ООП: наследование и полиморфизм (2020-03-03)
- MDN — Object.create
- javascript.info — Прототипы
- doka.guide — Object.create