Object.create()
Object.create() is one of the core methods for working with prototypes in JavaScript: it creates a new object whose prototype, that is, what it inherits from, you specify by hand. An optional second argument defines own properties through descriptors right away.
Theory
TL;DR
- Syntax:
Object.create(proto, [propertiesObject]). protobecomes the new object's[[Prototype]], which you can verify withObject.getPrototypeOf().- The second argument defines own properties as descriptors, exactly like
Object.defineProperty(). Object.create(null)creates an object with no prototype at all, handy as a dictionary.- It is the simplest form of prototypal inheritance without
classand constructors. - The new object does not copy the prototype's properties, it only links to them.
Quick example
const user = {
sayHi() {
console.log(`Hi, ${this.name}!`);
}
};
const alice = Object.create(user); // an object inheriting from user
alice.name = 'Alice';
alice.sayHi(); // "Hi, Alice!"Here user is the prototype ([[Prototype]]) of alice. The object alice has no sayHi of its own, it inherits it through the prototype.
Syntax and parameters
Object.create(proto, [propertiesObject])| Parameter | Description |
|---|---|
proto | The object that becomes the new object's prototype (or null) |
propertiesObject (optional) | Extra own properties, in descriptor form |
You can verify the result like this:
console.log(Object.getPrototypeOf(alice) === user); // trueObject.create() literally builds a new object whose internal [[Prototype]] is user.
An object with no prototype
const data = Object.create(null);
data.a = 1;
console.log(data); // { a: 1 }
console.log(Object.getPrototypeOf(data)); // null
console.log(data.toString); // undefinedSuch an object inherits nothing at all, not even toString or hasOwnProperty. It is used as a clean dictionary (a map object) where keys come from outside and must not collide with Object.prototype method names. The only downside: key checks have to go through Object.hasOwn(data, key) or 'a' in data.
The second argument: property descriptors
Properties can be defined with attributes straight away, as in Object.defineProperty():
const person = Object.create({}, {
name: { value: 'Alice', writable: false, enumerable: true },
age: { value: 25, writable: true }
});
console.log(person.name); // "Alice"
person.name = 'Bob'; // does not change the value
console.log(person.name); // "Alice"The second parameter accepts the same attributes: value, writable, enumerable, configurable, plus get and set. Remember that omitted attributes default to false here too, so age in the example will not show up in Object.keys().
Prototypal inheritance without classes
The most direct way to wire up inheritance by hand:
const Animal = {
eat() {
console.log('I eat');
}
};
const Dog = Object.create(Animal);
Dog.bark = function() {
console.log('Woof!');
};
Dog.eat(); // "I eat", inherited from Animal
Dog.bark(); // "Woof!", its own methodThe same approach replaces class once instance creation moves into an init method:
const UserProto = {
init(name) {
this.name = name;
return this;
},
greet() {
console.log(`Hi, ${this.name}`);
}
};
const user = Object.create(UserProto).init('Alice');
user.greet(); // "Hi, Alice"This style is common in functional OOP: no classes, but inheritance through the prototype.
Summary:
| What it does | Example | Result |
|---|---|---|
| Creates an object with a given prototype | Object.create(proto) | A new object whose [[Prototype]] = proto |
| Creates an object with no prototype | Object.create(null) | A "clean" object without toString or hasOwnProperty |
| Defines properties with attributes | Object.create({}, { key: { value: 1 } }) | The equivalent of defineProperty() |
| Implements inheritance | const child = Object.create(parent) | child inherits the properties of parent |
Common mistakes
- Confusing a prototype with a copy.
Object.create(proto)copies nothing: changeprotolater and the descendant sees the change. - Looking for inherited keys in
Object.keys(). It lists own properties only, whilefor...indoes walk the prototype chain, so loops needObject.hasOwn(). - Calling
Object.prototypemethods on anObject.create(null)object.data.hasOwnProperty('a')throwsTypeError; the correct form isObject.hasOwn(data, 'a')orObject.prototype.hasOwnProperty.call(data, 'a'). - Forgetting the
falsedefaults in the second argument. A property created throughpropertiesObjectwithout explicit attributes is neither writable nor enumerable. - Writing to an inherited property and expecting the prototype to change. The assignment creates an own property on the descendant and simply shadows the prototype's one instead of modifying it.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.