Object Oriented Java Script And Prototypal Inheritance
Conceptual Aside: Classical vs. Prototypal Inheritance
Inheritance where one object gets access to the properties and methods of another object.
Classical inheritance is the way that most programming languages handle inheritance. It's very robust but can get extremely complicated and intertwined.
Prototypal inheritance is used by JavaScript, and it's often much easier to understand.
Understanding the Prototype
All objects in JavaScript have a prototype property. The prototype property is a reference to another object.
Suppose I have an object with a property:
const obj = {
prop1: "Hello!"
};
obj.prop1; // "Hello"
obj.prop2; // What does this do?
When you reference an object property, there's a search order:
The JavaScript engine first looks in the object itself.
If it can't find the property, it then looks inside its prototype for the property name.
If it can't find it there, it looks inside the prototype's prototype, etc., etc.
This is known as the prototype chain.
Note: Notice that you don't have to manually reference the prototype. The JavaScript engine will automatically search down the prototype chain.
Accessing the prototype
You can directly set and access an object's prototype like this:
const person = {
name: "Default",
logName: function() { console.log(this.name) }
};
const dan = {
name: "Dan"
};
// THIS TECHNIQUE IS NOT PERFORMANT! DON'T EVER USE IT!
dan.__proto__ = person;
// Now this works...
dan.logName(); // logs "Dan"
Note: this
correctly references dan
, even though it's coming from the prototype person
.
Note 2: Notice that name
in dan
overrides name
in person
. That's because the prototype chain starts at the original object and stops searching when it finds the property.
Everything Is An Object (or A Primitive)
Everything in JavaScript reduces down to the base object prototype.
cons obj = {};
obj.__proto__; // Base object
const fn = function() { };
fn.__proto__; // Empty object containing apply, bind, call, etc.
fn.__proto__.__proto__; // Base object
const arr = [];
arr.__proto__; // Array object containing map, filter, length, etc.
arr__proto__.__proto__; // Base object
Reflection and Extend
Reflection is an object's ability to look at and change its own properties and methods.
const obj = {
prop1: 1,
prop2: 2
};
// We can access the properties of an object!
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) console.log(obj[prop]);
};
Extend is a useful code pattern that is an alternative to the prototype chain for combining and composing objects. Instead of inheriting properties and methods through the prototype chain, you can directly add new properties and methods through reflection.
// From underscore.js
_.extend(obj, { prop3: 3 });
The above method takes obj
and adds properties from all objects after it to obj
. That means obj
will now have prop3
.
Last updated