const - JS | lectureJavaScript OOP

Object.create

JavaScript OOP

In the previous lectures, we learned about constructor functions and ES6 classes, but there is actually a third way of implementing prototypal inheritance. And the third way is using the Object.create method, which works in a pretty different way than constructor functions and classes.

With Object.create, we still have the idea of prototypal inheritance. However, no prototype properties are involved, no constructor functions, and no new keyword. Instead, we can use the Object.create method to essentially set an object's prototype manually to any other object we want.

Hmmm, that sounds cool 😎. So if we can set the prototype to any object, let's create an object we want to use as the prototype of all the person objects we create. Essentially we will recreate the Person class from the previous lectures.

Let's assume we have a PersonProto object that will be used as the prototype of all the person objects we create.

index.js
const PersonProto = {
  // ...
};

Inside this object, we will add exactly what we added before in the prototype property of the Person class from the previous lectures.

index.js
const PersonProto = {
  calculateAge() {
    console.log(2022 - this.birthYear);
  },
};

Now, all we need to do is to create a person object, with PersonProto as the prototype.

index.js
const hart = Object.create(PersonProto);

This will now return a brand new object that is linked to the prototype that we passed into the Object.create method. In this case, PersonProto. So, hart is right now an empty object, and it will be linked to the PersonProto object, which will be its prototype.

Let's check that.

index.js
console.log(hart);

object-create-1

Let's add some properties to hart.

index.js
/**
 * This is not the best way to add properties to an object, but we will fix this later 😉
 */

hart.lastName = 'Hart';
hart.firstName = 'Louis';
hart.birthYear = 1991;
hart.profession = 'Developer';

With the properties added, we should now be able to calculate the age of hart.

index.js
hart.calculateAge(); // 31

And it works! ⚡️. So, just like before, we implemented prototypal inheritance but in a completely different way. And just to ensure that we are on the same page and that we understand this difference, let me show you a diagram of what's really happening here.

Below is a diagram showing how it works with constructor functions, just as we have been doing up until this point.

constructor-functions

So when we use the new operator in constructor functions or classes, it automatically sets the prototype of the newly created object to the constructor's prototype property. And that's nothing new to us.

On the other hand, with Object.create, we can set the prototype of objects manually to any object we want. And in this case, we manually set the prototype of hart to PersonProto.

object-create

And with this, the two objects are effectively linked through the __proto__ property just like before. So, now, looking up properties or methods in the prototype chain works just like it worked in function constructors or classes.

The big difference is that we didn't need any constructor function and no prototype property to achieve the same result. And this method is more straightforward, and sometimes, I feel like it's easier to understand. However, I showed you this technique at the end because it's not used that often in practice. But it's still good to know about it.

Let's get back to our code and verify what we just learned.

index.js
console.log(hart.__proto__); // { calculateAge: [Function: calculateAge] }

This makes sense because we explicitly said that PersonProto should be the prototype of hart when we created it with Object.create. Hence the following is also true.

index.js
console.log(hart.__proto__ === PersonProto); // true

Now that we understand what's going on here, let's create another person object.

index.js
const james = Object.create(PersonProto);

But now, instead of adding the properties manually, let's create a method that will programmatically add the properties to the object.

index.js
const PersonProto = {
  calculateAge() {
    console.log(2022 - this.birthYear);
  },

  // You can use any name
  build(firstName, lastName, birthYear, profession) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.birthYear = birthYear;
    this.profession = profession;
  },
};

We can now use this method to add properties to the object.

index.js
james.build('James', 'Hart', 1993, 'Developer');

If we now call the calculateAge method, it should work just like before.

index.js
james.calculateAge(); // 29

To finish this lecture, note that the build method above has nothing to do with the constructor functions that we saw in the previous lectures. And it is also completely different from the constructor method that we saw in classes. It's just a manual way of initializing the properties of an object.