#Objects#Prototypes

Object.create Polyfill

Implement Object.create using the classic empty-constructor trick to set an object's prototype chain.

By Pratik RaiMedium

Object.create builds a new object with a prototype you choose, optionally defining properties at the same time. It is the most direct way to work with JavaScript's prototypal inheritance without going through constructors or class syntax, and implementing it clarifies what a prototype chain actually is.

Prototypes in one paragraph

Every JavaScript object has an internal link to another object — its prototype. When you read a property that the object does not own, the engine follows that link, and keeps following it, until the property is found or the chain ends at null. That is the entire inheritance mechanism. class is syntax over it; Object.create sets the link directly.

What it does

JSfile.javascript
1const animal = { 2 describe() { return `${this.name} is a ${this.type}`; }, 3}; 4 5const dog = Object.create(animal); 6dog.name = 'Rex'; 7dog.type = 'dog'; 8 9dog.describe(); // "Rex is a dog" — method found on the prototype 10Object.getPrototypeOf(dog) === animal; // true 11dog.hasOwnProperty('describe'); // false — it is inherited, not owned

dog owns name and type. describe lives on animal and is reached through the chain.

The second argument accepts property descriptors, in the same shape Object.defineProperties uses:

JSfile.javascript
1const config = Object.create(null, { 2 apiUrl: { value: 'https://api.example.com', enumerable: true, writable: false }, 3});

Descriptor defaults are the opposite of what people expect: writable, enumerable and configurable all default to false. A property defined without specifying them is read-only and hidden from Object.keys.

Object.create(null) — the null-prototype object

Passing null produces an object with no prototype at all. That means no toString, no hasOwnProperty, no constructor — nothing inherited whatsoever.

This is genuinely useful for dictionaries:

JSfile.javascript
1const map = {}; 2map['toString']; // [Function: toString] — inherited, and probably not what you meant 3'constructor' in map; // true 4 5const safe = Object.create(null); 6safe['toString']; // undefined 7'constructor' in safe; // false

Using a plain {} as a lookup table means every key on Object.prototype appears to already exist. That is the root of a class of prototype-pollution bugs, and the reason Object.create(null) is the correct choice for any object keyed by untrusted input.

The trade-off is that such objects lack the usual methods. safe.hasOwnProperty(k) throws. Use Object.hasOwn(safe, k) or Object.prototype.hasOwnProperty.call(safe, k). Map is often the better answer outright — it accepts any key type and has no prototype concerns at all.

The implementation

Modern engines expose Object.setPrototypeOf, but the classic polyfill predates it and shows the mechanism more plainly:

JSfile.javascript
1Object.myCreate = function (proto, propertiesObject) { 2 if (typeof proto !== 'object' && typeof proto !== 'function') { 3 throw new TypeError('Object prototype may only be an Object or null'); 4 } 5 // typeof null === 'object', so null passes the guard above — which is correct. 6 7 function Temp() {} 8 Temp.prototype = proto; 9 const obj = new Temp(); 10 11 if (propertiesObject !== undefined) { 12 Object.defineProperties(obj, propertiesObject); 13 } 14 15 return obj; 16};

The trick is that new sets the new object's prototype to the constructor's prototype property. By pointing a throwaway constructor's prototype at the object you want and immediately calling new, you get an object with the right chain.

This classic version has one limitation it cannot escape: it cannot produce a true null-prototype object. Setting Temp.prototype = null causes new Temp() to fall back to Object.prototype. The genuine null case needs engine support — historically {__proto__: null}, today Object.setPrototypeOf.

Object.create versus the alternatives

Object.create(proto) sets the prototype at creation. Fast, and the engine can optimise the object's shape.

Object.setPrototypeOf(obj, proto) changes it afterwards. Correct but slow — mutating an existing object's prototype forces engines to deoptimise every call site that touched it. MDN warns against it explicitly. Use it only when you genuinely cannot set the prototype at creation.

class syntax is what you want for most inheritance. It handles constructor chaining, super, and static members. Object.create is for the cases where you want a prototype link without a constructor — mixins, dictionaries, delegation patterns.

Edge cases worth knowing

Descriptor defaults are false. Properties created through the second argument are non-writable, non-enumerable and non-configurable unless stated otherwise.

Prototype properties are shared. Mutating an object on the prototype affects every descendant. Assigning dog.name creates an own property that shadows rather than modifies — but dog.settings.theme = 'dark' mutates the shared object.

instanceof walks the chain. Object.create(Array.prototype) instanceof Array is true, even though it is not a real array and has no length behaviour.

Key takeaways

  • Object.create(proto) sets the prototype link directly at creation time.
  • Object.create(null) gives a dictionary with no inherited keys — the right choice for untrusted keys.
  • The second argument takes descriptors, and every flag defaults to false.
  • The classic polyfill uses a throwaway constructor and cannot produce a true null prototype.
  • Prefer creating with the right prototype over setPrototypeOf, which deoptimises.

Goal: Implement Object.myCreate with the empty-constructor trick and support for propertiesObject.

Frequently asked questions

What does Object.create do?
It creates a new object with its prototype set to the object you pass, without running any constructor. It is the most direct expression of prototypal inheritance in the language — no `new`, no class, just linking one object to another.
How do you implement it without setPrototypeOf?
The classic trick: create a throwaway constructor function, assign the desired prototype to its `prototype` property, and return `new F()`. The instance's internal prototype is set by construction, which is exactly what you wanted, and the empty constructor body means nothing else happens.
What is Object.create(null) for?
An object with no prototype at all, so it inherits nothing — no `toString`, no `hasOwnProperty`, and crucially no `__proto__` setter. That makes it the right choice for a dictionary keyed by untrusted strings, where a key named `constructor` or `__proto__` would otherwise collide with something inherited.
What does the second argument do?
It takes a property-descriptor map, the same shape `Object.defineProperties` accepts, letting you define properties with `writable`, `enumerable` and `configurable` set explicitly. Most implementations skip it, and being asked about it is usually a check on whether you know descriptors exist.

Related Challenges

Continue learning with these related challenges

View All
JavaScript

Object.assign Polyfill

Implement Object.assign from scratch: copy own enumerable properties (including Symbols) from sources onto the target.

JavaScript · Objects · PolyfillsPratik Rai ·

JavaScript

Array.prototype.groupBy

Group an array into buckets by a key function — now a real language feature as Object.groupBy.

JavaScript · ES6Pratik Rai ·

JavaScript

Recursive Object Evaluation

Implement a function that recursively traverses an object, evaluates functions with given arguments, and transforms keys to lowercase. Master recursive object traversal and type checking.

JavaScript · Recursion · ObjectsPratik Rai ·