ES6 Classes
In the previous lectures, we learned how to implement prototypal inheritance with constructor functions, and then manually setting methods on the constructor function's prototype property. But now, it's time to turn our attention to ES6 classes, which allows us to do the same thing, but using a nicer, and more modern syntax.
As mentioned earlier in the course, classes in JavaScript do not work like traditional classes in other languages like Java or C++. Instead, classes in JavaScript are just syntactic sugar over what we learned in the previous lectures. They still implement prototypal inheritance behind the scenes but with a syntax that is more familiar to developers coming from other languages.
Let's now implement Person
again, but this time using ES6 classes.
class Person {
// Do something
}
This is the class declaration syntax. And just like functions, we also have a class expression syntax.
const Person = class {
// Do something
};
This works because classes are just a special type of function. So although we use the class
keyword, behind the scenes, classes are still functions. Hence we have class expressions and class declarations. And I personally prefer the class declaration syntax.
Now that we have our class syntax, the first thing we need to do in our class is to add a constructor method.
class Person {
constructor() { // Do something // ... }}
The constructor method actually works in a pretty similar way as a constructor function. But in this case, it is a method of the class, and it needs to be called constructor. And just like in constructor functions, we pass in arguments basically for properties that we want the object to have.
class Person {
constructor(firstName, lastName, birthYear, profession) { // Do something
// ...
}
}
The act of creating a new object also works in the same way as before when using the new
operator. Hence, whenever we create a new object using the new
operator, the constructor method is automatically called.
Let's try that!
const william = new Person('William', 'Park', 1992, 'Designer');
You can see that when instantiating a new object, nothing changes. Everything looks the same as before. Therefore, just like before, the this
keyword inside the constructor method will point to the newly created empty object. Hence, like before, we can now add properties to the object using the this
keyword.
class Person {
constructor(firstName, lastName, birthYear, profession) {
this.firstName = firstName; this.lastName = lastName; this.birthYear = birthYear; this.profession = profession; }
}
Let's now have a look at the william
object.
console.log(william);
Nothing new here. It looks just like before.
So, in the constructor method, we basically have the properties that will be stored in the new object that we want to create. And so now let's add some methods to our class.
To add a method to a class, we simply add a method to the class body, just like we would do with an object.
class Person {
constructor(firstName, lastName, birthYear, profession) {
this.firstName = firstName;
this.lastName = lastName;
this.birthYear = birthYear;
this.profession = profession;
}
calculateAge() { console.log(2024 - this.birthYear); }}
Now what's important to understand here is that all the methods that we write in the class body i.e., outside of the constructor method, will be on the prototype of the objects, and not on the objects themselves.
And so now we can call the calculateAge
method on the william
object.
william.calculateAge(); // ==> 32
We can also check just to be sure that the __proto__
property of the william
object is the Person.prototype
object.
console.log(william.__proto__ === Person.prototype); // ==> true
The Person
class just acts like any other function constructor. The only difference is that the class syntax a nicer. With the class syntax, we don't have to manually mess with the prototype property. All we have to do is to write the methods in the class body, and they will automatically be added to the prototype property of the class.
We can actually take this demonstration even further by adding a method manually to the prototype property of the Person
class. And that's going to work just fine 😉.
Person.prototype.present = function () {
console.log(`Hi, I'm ${this.firstName} ${this.lastName}`);
};
Let's now call the present
method on the william
object.
william.present(); // ==> Hi, I'm William Park
This proves that the class really just hides the true nature of prototypal inheritance in JavaScript. So, of course, we could now do the same thing inside the class body. Remember 💡 to comment out the present
method that we just added to the prototype property of the Person
class.
class Person {
constructor(firstName, lastName, birthYear, profession) {
//...
}
calculateAge() {
console.log(2024 - this.birthYear);
}
present() { console.log(`Hi, I'm ${this.firstName} ${this.lastName}`); }}
Also, note that there are no commas between the methods in the class body. Now, if you try to call the present
method on the william
object, it should work just fine.
To finish this lecture, there are a couple of things we need to keep in mind when using classes in JavaScript.