Object.create()
Classes replaced it for inheritance. What survives is Object.create(null) — the way to build a dictionary that cannot collide with anything on Object.prototype.
Demo
The pair shows the new object own keys and the value it reads for x. In the first case the keys array is EMPTY while o.x is 1 — the value is found on the prototype, not on the object itself. That is the entire mechanism: create gives you a blank object that delegates lookups upward. It is also why Object.keys, Object.entries and JSON.stringify all see nothing here, while a plain property read succeeds. When the prototype has no x at all, the read is undefined rather than an error.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| proto | object | null | yes | The prototype for the new object. null creates an object with no prototype chain whatsoever. Any other primitive throws TypeError. |
| descriptors | object | no (none) | Property descriptors in the same shape Object.defineProperties takes — so properties added here are non-enumerable by default, exactly as with defineProperty. |
Return value
object — A new object with NO own properties, whose prototype is the object you passed. Passing null gives an object that inherits nothing at all.
Common patterns
const counts = Object.create(null); counts[userKey] = 1;
Object.assign(Object.create(Object.getPrototypeOf(src)), src);
class Dog extends Animal { }
Examples
Pitfalls
`${Object.create(null)}`
JSON.stringify(dict); Object.hasOwn(dict, k);
Object.keys(Object.create(null, {a: {value: 1}}))
Object.keys(Object.create(null, {a: {value: 1, enumerable: true}}))
const src = {x: 1}; const o = Object.create(src); src.x = 9; o.x
const o = {...src}; src.x = 9; o.x
Object.create(42)
Object.create(typeof p === "object" ? p : null)
When to use
- Dictionaries keyed by untrusted strings — Object.create(null)
- Copying an object while preserving its prototype
- Setting up a prototype chain without a constructor
- Creating an object with precisely specified descriptors
- Class-style inheritance → class and extends
- You want a copy → spread, Object.assign or structuredClone
- A keyed collection → a Map, which needs no prototype tricks
- The result will be string-coerced → a null prototype will throw
Notes
FAQ
Because a plain object inherits from Object.prototype, so keys like "toString" or "constructor" appear to exist before you set them, and a key of "__proto__" can change the prototype instead of storing a value. A null-prototype object has nothing to collide with. A Map avoids the problem entirely and is usually the better answer.
const d = Object.create(null); d.toString; // undefined, not a function