W3docs

JavaScript Prototype Methods Without __proto__

In the realm of web development, JavaScript stands as a cornerstone technology, enabling the creation of dynamic, interactive web applications. Among its many

Every JavaScript object is linked to another object called its prototype, and property lookups walk up that chain. The old way to read or change that link was the special __proto__ property, but it has real problems: it's an inherited accessor (not a normal data slot), it behaves inconsistently as an object key, and it can be exploited to corrupt objects. Modern JavaScript replaces it with explicit, predictable methods on the Object constructor.

This chapter shows the standard prototype methods — Object.create(), Object.getPrototypeOf(), and Object.setPrototypeOf() — and the inspection helpers Object.keys(), Object.values(), Object.entries(), and Object.hasOwn(). It then covers the most useful case for an object with no prototype: a safe "dictionary" for arbitrary keys.

For the bigger picture of how the chain works, see Prototypal Inheritance and Beyond.

Reading and Setting a Prototype

Use Object.getPrototypeOf() to read an object's prototype and Object.setPrototypeOf() to change it. These are the standardized replacements for reading and writing __proto__.

javascript— editable

Object.create(proto) builds a brand-new object whose prototype is exactly proto. It is the cleanest way to create an object with a chosen prototype without using __proto__ at all.

Why Avoid __proto__

__proto__ is a getter/setter defined on Object.prototype, not a property that lives on your object. That difference causes two practical issues:

  • It can fail or behave oddly as a data key. Because obj.__proto__ = value triggers the setter, you cannot reliably store a key literally named "__proto__" on an ordinary object — assigning a non-object is silently ignored, and assigning an object changes the prototype instead of adding a key.
  • It is a known attack surface ("prototype pollution"). Code that copies untrusted keys onto an object can be tricked into writing to __proto__, polluting Object.prototype for the whole program.

The standardized methods are explicit about intent: getPrototypeOf/setPrototypeOf change the prototype, while normal property writes never touch it.

javascript— editable

Objects Without a Prototype

Object.create(null) creates an object whose prototype is null. It inherits nothing — not even toString, hasOwnProperty, or the __proto__ accessor.

javascript— editable

The Dictionary Problem It Solves

A common pattern is using a plain object as a map from string keys to values. The trouble is that a plain {} already inherits keys from Object.prototype, so user-supplied keys like "constructor", "toString", or "__proto__" collide with the inherited names and break lookups.

javascript— editable

A null-prototype object has no inherited keys, so every key behaves exactly as written — including "__proto__":

javascript— editable

This is why null-prototype objects make safe dictionaries for untrusted keys. (The built-in Map is another good choice and allows non-string keys.)

Adding Methods to a Null-Prototype Object

Because there is no prototype to inherit from, you assign methods directly as own properties.

javascript— editable

Iterating Keys, Values, and Entries

Object.keys(), Object.values(), and Object.entries() return arrays of an object's own enumerable properties. Crucially, they ignore the prototype chain, so they work identically on normal and null-prototype objects. See Object.keys, values, entries for more.

javascript— editable

One caveat for null-prototype objects: they have no inherited toString, so passing one straight to template literals or String() throws. Iterate with the Object.* helpers (above) instead of relying on automatic string conversion.

Checking Own Properties with Object.hasOwn()

To test whether a key is the object's own property (not inherited), prefer Object.hasOwn(). It is the modern replacement for obj.hasOwnProperty() and works even on null-prototype objects, which don't have a hasOwnProperty method at all.

javascript— editable

Composition with Object.assign()

When you want one object to gain the behavior of several others, composition is often clearer than a single inheritance chain: an object can only have one prototype, but Object.assign(target, ...sources) can fold in methods from many sources by copying their own enumerable properties onto the target.

javascript— editable

Object.assign() also copies onto a null-prototype object, giving you a composed dictionary with no inherited surface:

javascript— editable

Shallow-copy caveat: Object.assign() copies property values, not deep clones. Object and array values are copied by reference, so the source and target share the same nested objects.

javascript— editable

For a deep, independent copy use structuredClone(source) instead.

Best Practices

  • Use the standardized methods, not __proto__. Reach for Object.create(), Object.getPrototypeOf(), and Object.setPrototypeOf(). Treat __proto__ as a legacy accessor to avoid in your own code.
  • Avoid changing prototypes after creation. Setting a chosen prototype at creation time with Object.create(proto) is cleaner and easier to reason about than mutating it later with Object.setPrototypeOf().
  • Use Object.create(null) (or Map) for dictionaries of untrusted keys. It removes inherited keys and prevents prototype-pollution surprises.
  • Prefer Object.hasOwn() over obj.hasOwnProperty(). It is shorter, safer to call, and works on null-prototype objects.
  • Compose with Object.assign() when you need behavior from multiple sources — just remember it is a shallow copy.

For related material, see Object methods and "this" and Property flags and descriptors.

Conclusion

The modern Object.* prototype methods give you explicit, predictable control over the prototype chain, replacing the quirky __proto__ accessor. Object.create(null) produces a clean, prototype-free object that is ideal for dictionaries, while Object.keys/values/entries, Object.hasOwn(), and Object.assign() let you inspect and compose objects safely regardless of their prototype.

Practice

Practice
Which call creates an object with no prototype, making it a safe dictionary for arbitrary keys?
Which call creates an object with no prototype, making it a safe dictionary for arbitrary keys?
Was this page helpful?