Object.create
Introduction
Object.create(proto) creates a new object whose internal [[Prototype]] is exactly proto. It is the most direct way to build prototype delegation without invoking a constructor function or using class.
Its second argument also lets you define properties with descriptors at creation time, which connects this API directly to property descriptors.
Why This Matters
Object.create is the cleanest way to explain prototype delegation. It also solves a real security and correctness problem: null-prototype dictionaries avoid accidental collisions with inherited names such as toString, constructor, or __proto__.
Theory
Basic form
Object.create(proto) returns a fresh empty object whose prototype is proto. Reads that miss on the new object continue on proto. Writes usually create or update own properties on the receiver, not on the prototype.
Second argument: descriptors
Object.create(proto, descriptors) works like creating the object and then calling Object.defineProperties. Descriptor defaults are the same strict defaults: omitted writable, enumerable, and configurable flags are false.
Null-prototype objects
Object.create(null) creates an object with no prototype at all. It does not inherit toString, valueOf, constructor, or hasOwnProperty. This is useful for dictionary-style data where every key should be user data, not inherited behaviour.
Trade-offs of null-prototype dictionaries
The benefit is no inherited-key collision. The cost is that common object methods are missing, so you must use safe static or borrowed APIs such as Object.keys(dict) and Object.prototype.hasOwnProperty.call(dict, key).
Relationship to inheritance
Constructor-function inheritance commonly uses Child.prototype = Object.create(Parent.prototype). That gives instances of Child a prototype chain that reaches Parent.prototype without running the parent constructor just to set up inheritance.
Visual Diagrams
const child = Object.create(parent)
child
+---------------------+
| own name: 'Ada' |
+---------------------+
|
v
parent
+---------------------+
| role: 'reader' |
+---------------------+
|
v
Object.prototype
+---------------------+
| toString, valueOf |
+---------------------+The created object starts empty but delegates missing reads to the prototype you pass in.
dictionary = Object.create(null)
+---------------------+
| apple: 2 |
| toString: 1 | own data key, not inherited method
+---------------------+
|
v
nullWith no prototype, every key is data you explicitly put there.
Code Examples
Create an object that delegates to defaults
The order has its own total but inherits currency from defaults.
Use a null-prototype dictionary
A null-prototype object is useful when user-provided keys should not collide with inherited object methods.
Playground
Press Run to execute the code and see output here.
Output Prediction
Predict the output #1
1const base = { role: 'reader' };2const user = Object.create(base);3 4user.name = 'Ada';5 6console.log(user.role);7console.log(Object.keys(user).join(','));8console.log(Object.getPrototypeOf(user) === base);Predict the output #2
1const obj = Object.create(null, {2 id: { value: 1, enumerable: true },3 hidden: { value: 2 }4});5 6console.log(Object.keys(obj).join(','));7console.log(obj.hidden);8console.log(Object.getPrototypeOf(obj));Coding Exercises
Build a safe string counter
MediumImplement countWords(words) so it returns a null-prototype dictionary mapping each word to its count. Keys like toString and constructor must be counted as normal words.
Interview Questions
1What does `Object.create(proto)` do?
It creates a new object whose internal [[Prototype]] is proto. The new object starts with no own properties unless descriptors are provided. Missing property reads delegate to proto through the prototype chain.
Follow-ups
- What happens if `proto` is `null`?
- How does the second argument work?
2Why would you use `Object.create(null)`?
It creates a dictionary object with no inherited keys. That prevents collisions with names like toString, constructor, or hasOwnProperty. The trade-off is that those inherited methods are unavailable, so you should use static or borrowed object utilities.
Quiz
1. What is the prototype of `Object.create(null)`?
2. What does the second argument to `Object.create` contain?
Summary
- `Object.create(proto)` creates an object with an explicit prototype.
- The second argument defines own properties through descriptors.
- `Object.create(null)` is useful for dictionary objects with no inherited-key collisions.
- Constructor-function inheritance commonly uses `Object.create(Parent.prototype)`.
Cheat Sheet
Basic: const child = Object.create(parent)
Null dictionary: const dict = Object.create(null)
With descriptors: Object.create(proto, { id: { value: 1, enumerable: true } })
Own keys: inherited properties do not appear in Object.keys(child).
Caution: null-prototype objects do not have hasOwnProperty as a method.