Object.setPrototypeOf()
Sets the prototype of an existing object to another object or to null.
Object.setPrototypeOf(obj, prototype)- Added in JavaScript ES2015
Parameters
| Parameter | Type | Description |
|---|---|---|
$obj | Object | The object which is to have its prototype set. |
$prototype | Object | null | The object's new prototype: an object, or null. |
Return value
ObjectThe specified object, obj.
Errors
Throws a TypeError if obj is null or undefined, if obj is non-extensible or an immutable prototype exotic object, or if prototype is neither an object nor null; no error is thrown when the new prototype equals the existing one.
Object.setPrototypeOf() rewires an object's [[Prototype]] after the object already exists. It works, it is standard, and it is almost always the wrong tool.
Why it is discouraged
Every engine optimises property access by assuming an object's shape and prototype are stable. Mutating the prototype invalidates the inline caches for that object and for any code that has touched it, and the deoptimisation is permanent for the affected code paths. Creating an object with the right prototype from the start avoids all of it:
// slow
const o = {};
Object.setPrototypeOf(o, parent);
// fast — same result
const o = Object.create(parent);
When it is still the right call
- Re-attaching a class prototype to data that crossed a boundary that strips it, such as
JSON.parse()output or a structured-clone result. There is no object to build from scratch, only one to repair. - Extending built-ins like
Errorwhen a transpiler target has broken the chain set up bysuper(). Object.setPrototypeOf(obj, null)to turn an existing object into a bare dictionary, so that keys likeconstructoror__proto__cannot collide with inherited members.
Outside those repair cases, prefer Object.create(), a class, or a factory function.
Example
When to use it
- Restore class methods on plain objects revived from JSON.parse
- Turn an existing object into a null-prototype dictionary to avoid key collisions
- Repair a broken prototype chain when subclassing a built-in under an old transpiler target
Frequently asked questions
Why is Object.setPrototypeOf considered slow?
Mutating an object's prototype invalidates the engine's inline caches for that object and any code that has already accessed it, permanently deoptimising those property lookups; Object.create() gives the same result with no penalty.
When should I use setPrototypeOf instead of Object.create?
Only when the object already exists and you cannot recreate it, such as re-attaching a class prototype to the result of JSON.parse() or a structured clone.
Why does setPrototypeOf throw a TypeError on my object?
Either the object is non-extensible (frozen or sealed), it is an immutable prototype exotic object such as Object.prototype, or the second argument is a primitive rather than an object or null.
More examples
Reviving class instances from JSON
JSON.parse() always produces plain objects, so the parsed data has the fields but none of the behaviour. Re-pointing the prototype restores the methods and makes instanceof pass, without re-running the constructor.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
length() {
return Math.hypot(this.x, this.y);
}
}
const revived = JSON.parse('{"x":3,"y":4}');
console.log(typeof revived.length); // "undefined"
Object.setPrototypeOf(revived, Point.prototype);
console.log(revived.length()); // 5
console.log(revived instanceof Point); // trueTurning an object into a bare dictionary
With the prototype removed, every inherited member disappears and only real data remains, so a key named toString can no longer be confused with the inherited method. Note that Object.hasOwn() still works on such an object while counts.hasOwnProperty() would throw.
const counts = { toString: 3, constructor: 1 };
console.log(typeof counts.valueOf); // "function" — inherited
Object.setPrototypeOf(counts, null);
console.log(counts.valueOf); // undefined
console.log(counts.toString); // 3 — own value, no longer shadowing
console.log(Object.keys(counts)); // [ 'toString', 'constructor' ]
console.log(Object.hasOwn(counts, "toString")); // true
Discussion