Object.setPrototypeOf() меняет прототип объекта.
Это довольно редкий метод. Его полезно знать, но в обычном коде им пользуются нечасто, потому что менять прототип уже созданного объекта обычно хуже, чем сразу создать объект с нужным прототипом.
Синтаксис
Object.setPrototypeOf(obj, prototype)
obj - объект, у которого нужно изменить прототип.
prototype - новый прототип. Это должен быть объект или null.
Что делает Object.setPrototypeOf()
Метод меняет прототип уже существующего объекта.
const animal = {
speak() {
console.log("sound");
},
};
const dog = {
name: "Rex",
};
Object.setPrototypeOf(dog, animal);
dog.speak(); // "sound"
После этого dog начинает наследоваться от animal.
Что возвращает метод
Object.setPrototypeOf() возвращает тот же самый объект.
const obj = {};
const proto = {};
const result = Object.setPrototypeOf(obj, proto);
console.log(result === obj); // true
Это важно: метод не создаёт новый объект, а меняет существующий.
Как проверить результат
После изменения прототип можно проверить через Object.getPrototypeOf().
const proto = { role: "user" };
const obj = {};
Object.setPrototypeOf(obj, proto);
console.log(Object.getPrototypeOf(obj) === proto); // true
console.log(obj.role); // "user"
Можно установить null
Новым прототипом может быть не только объект, но и null.
const user = {
name: "Anna",
};
Object.setPrototypeOf(user, null);
console.log(Object.getPrototypeOf(user)); // null
После этого объект перестаёт наследоваться от Object.prototype.
Object.setPrototypeOf() и Object.create()
Эти методы похожи по теме, но работают по-разному.
Object.create():
- сразу создаёт новый объект с нужным прототипом
Object.setPrototypeOf():
- берёт уже существующий объект
- и меняет его прототип потом
const proto = { role: "user" };
const a = Object.create(proto);
const b = {};
Object.setPrototypeOf(b, proto);
Если объект только создаётся, чаще предпочитают Object.create().
Почему метод используют редко
Изменение прототипа у уже созданного объекта обычно считается не лучшей практикой.
Причины простые:
- такой код сложнее читать
- он может быть медленнее
- чаще удобнее сразу создать объект правильно
Поэтому Object.setPrototypeOf() обычно оставляют для специальных случаев, а не для повседневного кода.
Когда метод выбрасывает ошибку
Если вторым аргументом передать не объект и не null, будет TypeError.
const obj = {};
Object.setPrototypeOf(obj, 123); // TypeError
Object.setPrototypeOf(obj, "proto"); // TypeError
null и undefined как target
Если первым аргументом передать null или undefined, тоже будет ошибка.
Object.setPrototypeOf(null, {}); // TypeError
Object.setPrototypeOf(undefined, {}); // TypeError
Примитивы
Если первым аргументом передать примитив, метод просто вернёт это значение обратно.
console.log(Object.setPrototypeOf(123, {})); // 123
console.log(Object.setPrototypeOf("hello", {})); // "hello"
Но полезной смены прототипа тут, конечно, не происходит.
Поэтому на практике метод используют именно с объектами.
Нерасширяемые объекты
Если объект уже нельзя расширять, смена прототипа на другой обычно вызовет ошибку.
const base = {};
const obj = Object.create(base);
Object.preventExtensions(obj);
Object.setPrototypeOf(obj, {}); // TypeError
Если же попытаться установить тот же самый прототип, ошибка обычно не возникает.
Object.setPrototypeOf() не копирует свойства
Метод не переносит свойства из нового прототипа в сам объект.
Он только меняет цепочку наследования.
const base = { role: "user" };
const obj = {};
Object.setPrototypeOf(obj, base);
console.log(obj.role); // "user"
console.log(obj.hasOwnProperty("role")); // false
Свойство role здесь пришло из прототипа, а не стало собственным свойством obj.
Object.setPrototypeOf() и isPrototypeOf()
После изменения прототипной цепочки это легко проверить.
const base = {};
const obj = {};
Object.setPrototypeOf(obj, base);
console.log(base.isPrototypeOf(obj)); // true
То есть один метод меняет цепочку, а другой помогает проверить результат.
Объекты без прототипа
Метод можно использовать и с объектами, созданными через Object.create(null).
const dict = Object.create(null);
const proto = { type: "base" };
Object.setPrototypeOf(dict, proto);
console.log(Object.getPrototypeOf(dict) === proto); // true
Это редкий, но возможный сценарий.
Когда это полезно
Object.setPrototypeOf() удобно использовать, когда:
- нужно явно поменять прототип уже существующего объекта
- вы работаете с метапрограммированием или низкоуровневой логикой объектов
- объект нельзя пересоздать, а прототипную цепочку нужно изменить
Но в обычном приложении такие случаи встречаются редко.
Частые ошибки
Думать, что метод создаёт новый объект
const obj = {};
const proto = {};
const result = Object.setPrototypeOf(obj, proto);
console.log(result === obj); // true
Метод работает с тем же самым объектом.
Путать смену прототипа и копирование свойств
const proto = { role: "user" };
const obj = {};
Object.setPrototypeOf(obj, proto);
console.log(obj.role); // "user"
console.log(obj.hasOwnProperty("role")); // false
Свойство доступно через прототип, но не копируется в сам объект.
Использовать метод там, где проще Object.create()
const proto = { role: "user" };
const obj = {};
Object.setPrototypeOf(obj, proto);
Если объект только создаётся, обычно проще и понятнее сразу написать:
const obj = Object.create(proto);
Быстрая памятка
Object.setPrototypeOf()меняет прототип уже существующего объекта- метод возвращает тот же самый объект
- новый прототип должен быть объектом или
null - метод не копирует свойства, а меняет только цепочку наследования
- в обычном коде чаще предпочитают
Object.create()
Коротко
Object.setPrototypeOf() - это способ вручную поменять прототип объекта. Главное, что стоит запомнить: метод не создаёт новый объект и не копирует свойства, а просто перестраивает прототипную цепочку, поэтому использовать его стоит только там, где это действительно нужно.