Learn about prototypal inheritance in JavaScript.
This material is part of the mobile development course for Media Engineering.
You will need
Recommended reading
JavaScript is a little different than class-based languages like Java or C++ when it comes to inheritance. In JavaScript, the only constructs when it comes to inheritance are objects.
Objects Inherit From Other Objects
While this is often considered to be one of JavaScript's weaknesses, the prototypal inheritance model itself is, in fact, more powerful than the classic model. It is, for example, fairly trivial to build a classic model on top of a prototypal model.
JavaScript Prototypes > Prototypal inheritance
Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain.
let o = {};console.log(o.__proto__); // {}console.log(o.__proto__.__proto__); // nullconsole.log(Object.getPrototypeOf(o)); // {}console.log(Object.getPrototypeOf(Object.getPrototypeOf(o))); // null
Nearly all objects in JavaScript are instances of Object
which sits on the top of a prototype chain:
let o = {};console.log(Object.getPrototypeOf(o) === Object.prototype); // true
When trying to access a property of an object, the property will not only be sought on the object but also on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.
JavaScript Prototypes > Prototypal inheritance
There are 3 ways to create objects in JavaScript.
The first way is to create a plain or literal object with curly braces, like so:
const person = { firstName: 'Bob', lastName: 'Page' };console.log(person.firstName); // "Bob"console.log(person.foo); // undefined// The prototype of "person" is "Object.prototype".let prototypeOfPerson = Object.getPrototypeOf(person);console.log(prototypeOfPerson === Object.prototype); // true// "Object.prototype" is the top of the inheritance chain. Its prototype is null.let prototypeOfObject = Object.getPrototypeOf(Object.prototype);console.log(prototypeOfObject === null); // true
Note that when we tried to access foo
,
a property that doesn't exist on person
or on Object.prototype
, we got undefined
.
Object.create
JavaScript Prototypes > Prototypal inheritance
The second way to create objects is using Object.create
,
which creates a new object with the specified prototype.
This means that our new object, instead of having Object.prototype
as its prototype,
will have the object we passed to Object.create
as its prototype:
const person = { firstName: 'Bob', lastName: 'Page' };// Create an object with a prototype.const child = Object.create(person);// The prototype of "child" is "person".let prototypeOfChild = Object.getPrototypeOf(child);console.log(prototypeOfChild === person); // true// The prototype of "person" is "Object.prototype".let prototypeOfPerson = Object.getPrototypeOf(person);console.log(prototypeOfPerson === Object.prototype); // true
JavaScript Prototypes > Prototypal inheritance > Creating objects with Object.create
But what can we do with that object?
const person = { firstName: 'Bob', lastName: 'Page' };// Create an object with a prototype.const child = Object.create(person);child.age = 12;console.log(child.age); // 12console.log(child.firstName); // "Bob"console.log(child.foo); // undefined
This is what happens when you access child.age
:
Obviously, we can retrieve that property since we just added it to child
.
JavaScript Prototypes > Prototypal inheritance > Creating objects with Object.create
But what can we do with that object?
const person = { firstName: 'Bob', lastName: 'Page' };// Create an object with a prototype.const child = Object.create(person);child.age = 12;console.log(child.age); // 12console.log(child.firstName); // "Bob"console.log(child.foo); // undefined
This is what happens when you access child.firstName
:
child
doesn't have a firstName
property,
so JavaScript will move on to the next object in the prototype chain, and check if that object has it.
Since person
is the prototype of child
, and it has a firstName
property, we get its value.
JavaScript Prototypes > Prototypal inheritance > Creating objects with Object.create
But what can we do with that object?
const person = { firstName: 'Bob', lastName: 'Page' };// Create an object with a prototype.const child = Object.create(person);child.age = 12;console.log(child.age); // 12console.log(child.firstName); // "Bob"console.log(child.foo); // undefined
This is what happens when you access child.foo
:
In this case, neither child
, person
nor Object.prototype
have a property called foo
,
so after moving all the way up the prototype chain and having found no matching property, JavaScript returns undefined
.
JavaScript Prototypes > Prototypal inheritance > Creating objects with Object.create
What happens if you add a property with the same name to the child
object?
const person = { firstName: 'Bob', lastName: 'Page' };// Create an object with a prototype.const child = Object.create(person);child.firstName = 'Megan';console.log(child.firstName); // "Megan"console.log(child.lastName); // "Page"
When you access child.firstName
, it returns its own property:
When you access child.lastName
, it returns its prototype's property:
JavaScript Prototypes > Prototypal inheritance
function Person(first, last) { this.first = first; this.last = last;}// Check that our function has an associated prototype object.console.log(typeof(Person.prototype)); // "object"// Create an object by calling the function as a constructor.const child = new Person('Bob', 'Page');let prototypeOfChild = Object.getPrototypeOf(child);console.log(prototypeOfChild === Person.prototype); // truelet prototypeOfPerson = Object.getPrototypeOf(Person.prototype);console.log(prototypeOfPerson === Object.prototype); // true
Every function has an associated prototype object which you can access by its prototype
property.
When you use that function as a constructor with new
, the prototype of the created object will be the function's prototype object.
JavaScript Prototypes > Prototypal inheritance
Let's combine two of the important things we just learned:
Wait, what?
This means that if we attach things to a function's prototype object, these things will be available on any object constructed with that function.
Welcome to your first JavaScript-class-without-a-class:
// Define a "class".function Person(first, last) { this.first = first; this.last = last;}// Add a "method" to the "class".Person.prototype.getFullName = function() { return `${this.first} ${this.last}`;};// Construct an object.const person = new Person('Bob', 'Page');// Access properties like before.console.log(person.first); // "Bob"// Call a method.console.log(person.getFullName()); // "Bob Page"
this
JavaScript Prototypes > Implementing a class-like structure with prototypes
Note that when calling a function on an object,
the keyword this
always refers to the object the function was called on.
const o = { value: 24, getValue: function() { return this.value }};console.log(o.getValue()); // 24
function Foo() { this.value = 42;}Foo.prototype.getValue = function() { return this.value;};const o = new Foo();console.log(o.getValue()); // 42
By the way, it's best to use the second structure rather than the first.
Why? Because in the first example, a new function will be created every time you create an object this way.
In the second example, only one getValue
function is defined and attached to the prototype, and it's reused for every object that's an instance of Foo
.
Documentation
Further reading
Learn about prototypal inheritance in JavaScript.
This material is part of the mobile development course for Media Engineering.
You will need
Recommended reading
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |