JavaScript Prototypes
Last updated:
A concept unique to JavaScript, is a powerful way to add functionality (properties and methods) to objects.
The Prototype Object
Every object has an internal prototype property which allows an object to inherit properties and methods from another object.
When you create a new object in JavaScript, it inherits all the properties and methods from its prototype. This is called prototypal inheritance and allows us to create complex objects by reusing existing code.
The prototype property is an object itself, and it’s accessed using the __proto__
property or the Object.getPrototypeOf()
method.
Using a Prototype
Object.create()
Method that can be used to create an object with a specified prototype object and properties:
const personPrototype = {
sayHello: function() {
console.log(`Hello ${this.name}`);
}
};
let person = Object.create(personPrototype, {
name: { value: 'Paul' }
});
person.sayHello(); // Outputs: Hello Paul
console.log(person.__proto__);
// Outputs: "{ sayHello: [Function: sayHello] }"
Object properties can also be set after the object was created:
let person = Object.create(personPrototype);
person.name = 'Paul';
person.sayHello(); // Outputs: Hello Paul
Object.setPrototypeOf
We can use Object.setPrototypeOf
to set a prototype after an object has been created:
let person = {
name: 'Paul'
};
person.sayHello(); // Uncaught TypeError:
// person.sayHello is not a function
const personPrototype = {
sayHello: function() {
console.log(`Hello ${this.name}`);
}
};
Object.setPrototypeOf(person, personPrototype);
person.sayHello(); // Outputs: Hello Paul
Using __proto__
The __proto__
property can be used to set an object’s prototype:
let developer = {
language: 'JavaScript'
};
let person = {
name: 'Paul',
__proto__: developer
};
console.log(person.name); // Outputs: Paul
console.log(person.language); // Outputs: Paul
new
keyword
Objects can also be created using a constructor function:
function Person(name) {
this.name = name;
}
var person = new Person("Paul");
console.log(person.name); // Outputs: Paul
In this instance, methods can be added to the Person.prototype
object directly:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log(`Hello ${this.name}`);
};
var person = new Person("Paul");
person.sayHello(); // prints: Hello Paul
Overriding a Prototype Method
A prototype method can be overridden simply by assigning a new value:
const personPrototype = {
sayHello: function() {
console.log(`Hello ${this.name}`);
}
};
let person = Object.create(personPrototype, {
name: { value: 'Paul' }
});
person.sayHello(); // prints: Hello Paul
// Override the `sayHello` method
person.sayHello = function() {
console.log(`Good afternoon ${this.name}`);
};
person.sayHello(); // prints: Good afternoon Paul
Prototype Chain
Here is a prototype chain that will make things a bit clearer. Remember, a prototype is simply an object itself:
const personPrototype = {
name: 'World'
sayHello: function() {
console.log(`Hello ${this.name}`);
}
};
let person = Object.create(personPrototype);
// the `person` object will serve as the prototype
// for a new `paul` object
let paul = Object.create(person, {
name: { value: 'Paul' }
});
paul.sayHello(); // prints: Hello Paul
Notice that the paul
object doesn’t have a sayHello
method so JavaScript looks for it in its prototype chain and finds the sayHello
method on the personPrototype object.
Introspection
You can check an object’s prototype using the instanceof
operator or the Object.getPrototypeOf()
const personPrototype = {
sayHello: function() {
console.log(`Hello ${this.name}`);
}
};
let person = Object.create(personPrototype, {
name: { value: 'Paul' }
});
console.log(person.__proto__);
// prints: "{ sayHello: [Function: sayHello] }"
console.log(person instanceof Object); // true
console.log(Object.getPrototypeOf(person) === personPrototype); // true
Take Away
- prototypes are a powerful feature that allows for easy code reuse and inheritance.
- every object has a prototype, except for
Object.prototype
which is the root of the prototype chain. When you try to access a property or method on an object, JavaScript first looks for it on the object itself. If it’s not found, it looks for it on the object’s prototype, and so on up the prototype chain until it reachesObject.prototype
. - the
Object.setPrototypeOf()
method can be used to set an object’s prototype, but not recommended due to possible negative impact on performance. - the prototype property is accessed using the
__proto__
property or theObject.getPrototypeOf()
method. - when you create an object using a constructor function with the
new
keyword, JavaScript automatically sets the object’s prototype to be theprototype
property of the constructor function. - you can check an object’s prototype using the
instanceof
operator or theObject.getPrototypeOf()