Object.getPrototypeOf()

The standard replacement for the __proto__ accessor. Its companion setPrototypeOf exists too, and every engine documentation entry for it amounts to a warning not to call it.

Object static methodES5 (2009)Live demo
Common call
Object.getPrototypeOf(o)
Returns
the prototype object, or null
Replaces
the legacy __proto__ accessor
Watch out
setPrototypeOf deoptimises the object permanently
Object.getPrototypeOf(objectobject — The object to inspect. Primitives are coerced to their wrapper, so a number yields Number.prototype. null and undefined throw TypeError.type: object · required)
→ object | null

Demo

Live evaluation
Try:
Inputs
jsonstringa JSON object or array
Output
(p => [p === Object.prototype, p === Array.prototype])(Object.getPrototypeOf(JSON.parse('{"a":1}')))
[true, false]

A prototype object cannot be printed usefully, so the demo reports which well-known prototype was found. A plain object gives [true, false] — its prototype is Object.prototype. An array gives [false, true], because its prototype is Array.prototype, which is where every array method lives. Array.prototype in turn has Object.prototype above it, which is how an array ends up with both push and hasOwnProperty. That two-step chain is exactly what instanceof walks.

Parameters

NameTypeRequiredDescription
objectobjectyesThe object to inspect. Primitives are coerced to their wrapper, so a number yields Number.prototype. null and undefined throw TypeError.

Return value

object | null — The object prototype — one link up the chain. null for an object created with Object.create(null), and for Object.prototype itself.

Common patterns

Copy an object with its prototype
Spread and assign both flatten to a plain object.
Object.assign(Object.create(Object.getPrototypeOf(src)), src);
Detect a plain object
More precise than typeof.
const isPlain = o != null &&
  (Object.getPrototypeOf(o) === Object.prototype ||
   Object.getPrototypeOf(o) === null);
Set the prototype at creation, not after
Avoids the deoptimisation entirely.
const o = Object.create(proto);

Examples

1. Plain object
Object.getPrototypeOf({}) === Object.prototype
Returns
true
2. Array
Object.getPrototypeOf([]) === Array.prototype
Returns
true
3. Null prototype
Object.getPrototypeOf(Object.create(null))
Returns
null
4. Top of the chain
Object.getPrototypeOf(Object.prototype)
Returns
null
5. Primitives coerce
Object.getPrototypeOf(42) === Number.prototype
Returns
true
6. null throws
Object.getPrototypeOf(null)
Returns
TypeError: Cannot convert undefined or null to object

Pitfalls

1. setPrototypeOf is genuinely slow
Changing an object prototype after creation invalidates every inline cache that has ever seen it, and engines deoptimise the object permanently. It is one of the few operations that engine maintainers actively advise against. Build the object with the right prototype instead.
Deoptimises
const o = {};
Object.setPrototypeOf(o, proto);
works, but the object is now slow
Create it correctly
const o = Object.create(proto);
no penalty
2. It returns null at the top of the chain
Object.prototype has no prototype, and neither does an Object.create(null) object. Code that walks the chain must stop on null or it throws on the next iteration.
Throws eventually
let p = o;
while (true) p = Object.getPrototypeOf(p);
TypeError once p is null
Stop at null
let p = o;
while ((p = Object.getPrototypeOf(p)) !== null) { }
terminates
3. It is one link, not the whole chain
A single call goes up exactly one level. Finding whether a method is reachable means looping, or using instanceof or isPrototypeOf, both of which walk the chain for you.
One level only
Object.getPrototypeOf([]) === Object.prototype
false — it is Array.prototype
Walk it
Object.prototype.isPrototypeOf([])
true
4. __proto__ is the legacy form, and a hazard in data
The accessor still works but is Annex B. Worse, assigning a key named __proto__ on a plain object CHANGES its prototype rather than storing a value, which is the basis of prototype-pollution attacks on parsed JSON.
Changes the prototype
const o = {};
o.__proto__ = {polluted: 1};
Object.getPrototypeOf(o).polluted
1
Null-prototype dictionary
const d = Object.create(null);
d.__proto__ = {x: 1};
stored as a normal key

When to use

Use it
  • Copying an object while preserving its prototype
  • Distinguishing a plain object from a class instance
  • Introspection and debugging of a prototype chain
  • Reaching a prototype to list its methods
Reach for something else
  • Changing a prototype after creation → Object.create, or a class
  • Checking a chain relationship → instanceof or isPrototypeOf
  • Reading __proto__ → this is its standard replacement
  • Building a dictionary → Object.create(null) or a Map

Notes

Complexity
O(1) to read; setPrototypeOf is O(1) but triggers deoptimisation
Return
The prototype object, or null; nothing is allocated
CPython impl
V8: Builtins-object-getprototypeof
Memory
No allocation
Thread-safe
Single-threaded; reading is always safe

FAQ

getPrototypeOf. The __proto__ accessor is Annex B — normatively optional, kept only for web compatibility — and it is the vector for prototype pollution when it appears as a key in untrusted data. The static method has neither problem.

Object.getPrototypeOf(o);   // standard
o.__proto__;                // legacy

History

ES5
getPrototypeOf added as the standard alternative to __proto__.
ES2015
setPrototypeOf standardised, and __proto__ documented in Annex B as legacy.