Object.getPrototypeOf and Object.setPrototypeOf in JS
JavaScript relies on prototype-based inheritance, where objects
inherit properties and methods from other objects via an internal link
known as [[Prototype]]. This article explains how
Object.getPrototypeOf() and
Object.setPrototypeOf() interact with this mechanism. You
will learn their syntax, core behaviors, return values, edge cases, and
the critical performance implications associated with mutating an
object’s prototype at runtime.
Object.getPrototypeOf()
Object.getPrototypeOf() returns the prototype (the value
of the internal [[Prototype]] property) of the specified
object.
Syntax
Object.getPrototypeOf(obj)Behavior and Return Value
- Standard Objects: Returns the prototype object linked to the target object.
- Objects without Prototypes: If an object is created
with
Object.create(null), the method returnsnull. - Primitives: In ES6 and later, passing a non-object primitive (e.g., number, string, boolean) automatically coerces the value into its corresponding object wrapper before retrieving the prototype.
nullandundefined: Passingnullorundefinedthrows aTypeError.
Example
const parent = { greeting: "Hello" };
const child = Object.create(parent);
console.log(Object.getPrototypeOf(child) === parent); // true
// Coercion of primitives
console.log(Object.getPrototypeOf("text") === String.prototype); // trueObject.setPrototypeOf()
Object.setPrototypeOf() sets the prototype (i.e., the
internal [[Prototype]] property) of a specified object to
another object or null.
Syntax
Object.setPrototypeOf(obj, prototype)Behavior and Return Value
- Return Value: Returns the modified object itself.
- Valid Prototypes: The second argument must be an
Objectornull. Passing any other value will throw aTypeErroror silently fail if the target is not an object. - Prototype Cycles: If setting a prototype causes a
circular prototype chain (an object attempting to inherit from itself
directly or indirectly), a
TypeError(“Cyclic proto value”) is thrown. - Non-Extensible Objects: If the target object is
non-extensible (via
Object.preventExtensions(),Object.seal(), orObject.freeze()), changing its prototype throws aTypeError. - Primitives: If the first argument is a primitive, it cannot be mutated. The method simply returns the primitive without error and does not assign a prototype.
Example
const animal = {
speak() {
return `${this.name} makes a sound.`;
}
};
const dog = { name: "Rex" };
// Assign prototype
Object.setPrototypeOf(dog, animal);
console.log(dog.speak()); // "Rex makes a sound."
console.log(Object.getPrototypeOf(dog) === animal); // truePerformance Considerations
While Object.getPrototypeOf() is a fast, standard read
operation, Object.setPrototypeOf() is considered a
performance anti-pattern in modern JavaScript engines:
- Deoptimization: JavaScript engines optimize
property access by tracking object shapes (hidden classes). Mutating an
object’s prototype chain via
Object.setPrototypeOf()invalidates these optimizations, causing code that accesses properties on the affected objects to execute significantly slower. - Best Practice Alternative: Whenever possible,
assign prototypes at object creation time using
Object.create()or ES6classsyntax with theextendskeyword, rather than mutating an existing object’s prototype chain.
// Preferred approach instead of setPrototypeOf
const dog = Object.create(animal);
dog.name = "Rex";