The Object.setPrototypeOf()
static method sets the prototype (i.e., the internal <span class="createlink">Prototype</span>
property) of a specified object to another object or null
.
Warning: Changing the
<span class="createlink">Prototype</span>
of an object is, by the nature of how modern JavaScript engines optimize property accesses, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to the time spent in theObject.setPrototypeOf(...)
statement, but may extend to any code that has access to any object whose<span class="createlink">Prototype</span>
has been altered. You can read more in JavaScript engine fundamentals: optimizing prototypes.Because this feature is a part of the language, it is still the burden on engine developers to implement that feature performantly (ideally). Until engine developers address this issue, if you are concerned about performance, you should avoid setting the
<span class="createlink">Prototype</span>
of an object. Instead, create a new object with the desired<span class="createlink">Prototype</span>
using Object.create.
Syntax
Object.setPrototypeOf(obj, prototype)
Parameters
obj
- : The object which is to have its prototype set.
prototype
- : The object's new prototype (an object or
null
).
- : The object's new prototype (an object or
Return value
The specified object.
Exceptions
- TypeError
- : Thrown in one of the following cases:
- The
obj
parameter isundefined
ornull
. - The
obj
parameter is non-extensible, or it's an immutable prototype exotic object, such asObject.prototype
orwindow
. However, the error is not thrown if the new prototype is the same value as the original prototype ofobj
. - The
prototype
parameter is not an object ornull
.
- The
- : Thrown in one of the following cases:
Description
Object.setPrototypeOf()
is generally considered the proper way to set the prototype of an object. You should always use it in favor of the deprecated Object.prototype.__proto__
accessor.
If the obj
parameter is not an object (e.g. number, string, etc.), this method does nothing — without coercing it to an object or attempting to set its prototype — and directly returns obj
as a primitive value. If prototype
is the same value as the prototype of obj
, then obj
is directly returned, without causing a TypeError
even when obj
has immutable prototype.
For security concerns, there are certain built-in objects that are designed to have an immutable prototype. This prevents prototype pollution attacks, especially proxy-related ones. The core language only specifies Object.prototype
as an immutable prototype exotic object, whose prototype is always null
. In browsers, window
and location
are two other very common examples.
Object.isExtensible(Object.prototype); // true; you can add more properties
Object.setPrototypeOf(Object.prototype, {}); // TypeError: Immutable prototype object '#<Object>' cannot have their prototype set
Object.setPrototypeOf(Object.prototype, null); // No error; the prototype of `Object.prototype` is already `null`
Examples
Pseudoclassical inheritance using Object.setPrototypeOf()
Inheritance in JS using classes.
class Human {}
class SuperHero extends Human {}
const superMan = new SuperHero();
However, if we want to implement subclasses without using class
, we can do the following:
function Human(name, level) {
this.name = name;
this.level = level;
}
function SuperHero(name, level) {
Human.call(this, name, level);
}
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);
// Set the `<span class="createlink">Prototype</span>` of `SuperHero.prototype`
// to `Human.prototype`
// To set the prototypal inheritance chain
Human.prototype.speak = function () {
return `${this.name} says hello.`;
};
SuperHero.prototype.fly = function () {
return `${this.name} is flying.`;
};
const superMan = new SuperHero("Clark Kent", 1);
console.log(superMan.fly());
console.log(superMan.speak());
The similarity between classical inheritance (with classes) and pseudoclassical inheritance (with constructors' prototype
property) as done above is mentioned in Inheritance chains.
Since function constructors' prototype
property is writable, you can reassign it to a new object created with Object.create()
to achieve the same inheritance chain as well. There are caveats to watch out when using create()
, such as remembering to re-add the constructor
property.
In the example below, which also uses classes, SuperHero
is made to inherit from Human
without using extends
by using setPrototypeOf()
instead.
Warning: It is not advisable to use
setPrototypeOf()
instead ofextends
due to performance and readability reasons.
class Human {}
class SuperHero {}
// Set the instance properties
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);
// Hook up the static properties
Object.setPrototypeOf(SuperHero, Human);
const superMan = new SuperHero();
Subclassing without extends
is mentioned in ES-6 subclassing.