What Are Classes, Objects and Constructors in Javascript
What Are Classes, Objects and Constructors in Javascript

Hello and welcome back to the channel. In this video you will learn how object oriented programming is implemented in Javascript by comparing Es6 classes approach with prototypes approach.

Let's jump right into it.

If you don't know starting with ES6 we got classes in Javascript. So code looks really nice and clean but it's nothing more that a sugar on the top of prototypes. So there is 0 new entities or behavior in classes compared with prototypes. It's just a sugar and let's build a small example so we can understand it better.

For example we want a class to create tracks.

class Track {
  constructor(params) {
    this.name = params.name;
    this.url = params.url;
  }

  playTrack() {
    console.log(`We started playing ${this.name}`);
  }
}


var track01 = new Track({
  name: "track01",
  url: "track01.mp3",
});

var track02 = new Track({
  name: "track02",
  url: "track02.mp3",
});

console.log(track01);
console.log(track02);

track01.playTrack();
track02.playTrack();

Here we created a class Track using reserved class keyword. Just to remind you classes don't work in older browsers and you need to transpile code in prototypes. We are using constructor in classes so we can pass some properties when we create an instance of the class. We also created a method playTrack which we can call on our tracks.

So as you can see in browser everything is working and our code is clean and supportable.

Now let's look on the inheritance. We need inheritance to get all methods and properties from the class from which we create our new class. Let's make a new class YoutubeTrack and extend it from Track class.

class YoutubeTrack extends Track {}


var youtubeTrack01 = new YoutubeTrack({
  name: "youtubeTrack01",
  url: "youtubeTrack01.mp3",
  image: "track01.jpg",
});

var youtubeTrack02 = new YoutubeTrack({
  name: "youtubeTrack02",
  url: "youtubeTrack02.mp3",
  image: "track02.jpg",
});

console.log(youtubeTrack01);
console.log(youtubeTrack02);
youtubeTrack01.playTrack();
youtubeTrack02.playTrack();

As you can see just with single like we got the whole behavior from Track to YoutubeTrack. This is the inheritance. What we can also do is override methods and properties.

class YoutubeTrack extends Track {
  constructor(params) {
    super(params);
    this.image = params.image;
  }

  playTrack() {
    console.log(`Hello youtube ${this.name}`);
  }

So here we overrode constructor and playTrack. The most interesting part is this super call. If we override constructor than the constructor of the parent is not being called. If we want to call it and do something else we can call super. It's the same like calling the constructor of the parent directly.

So this is how inheritance and classes are working in all modern browsers. But you need to understand that all in Javascript world are based on functions and prototypes because there is no such entity as a class in Javascript. Let's rewrite the same code by using pure prototypes.

var Track = function (params) {
  this.name = params.name;
  this.url = params.url;

  // this.playTrack = function () {
  //   console.log('We started playing ', this.name);
  // };
};

Track.prototype.playTrack = function () {
  console.log("We started playing ", this.name);
};

var track01 = new Track({
  name: "track01",
  url: "track01.mp3",
});

var track02 = new Track({
  name: "track02",
  url: "track02.mp3",
});

console.log(track01);
console.log(track02);

track01.playTrack();
track02.playTrack();

So here we create a function Track and used this inside. Now we can create instances from our function and have properties inside.
So actually our initial function is a constructor. Also as you can see we can specify methods inside a constructor with this.somename. We can also specify them outside of constructor function by using prototype keyword.


Now let's look how we can create inheritance using prototypes. And this will for sure not look that nice like with classes sugar.

var YoutubeTrack = function (params) {
  Track.apply(this, arguments);
  this.image = params.image;
};


var youtubeTrack01 = new YoutubeTrack({
  name: "youtubeTrack01",
  url: "youtubeTrack01.mp3",
  image: "track01.jpg",
});

var youtubeTrack02 = new YoutubeTrack({
  name: "youtubeTrack02",
  url: "youtubeTrack02.mp3",
  image: "track02.jpg",
});

console.log(youtubeTrack01);
console.log(youtubeTrack02);
youtubeTrack01.playTrack();
youtubeTrack02.playTrack();

So here we used Track.apply as an alternative to super from classes approach.

But we also get an error

youtubeTrack01.playTrack is not a function

This is happening because we didn't implement extending this is why we don't get playTrack function inside prototype.

YoutubeTrack.prototype = Object.create(Track.prototype);

Now everything is working and we used Object create to make a copy of Track.prototype and avoid reference link.

But we have 1 more problem. If we write YoutubeTrack.prototype.constructor you can see that we didn't update it and it has the code of Track constructor. To do this we can just override it with our YoutubeTrack.

YoutubeTrack.prototype.constructor = YoutubeTrack;

With this line we brought correct constructor to YoutubeTrack.

So as you see classes is a great sugar in Javascript to bring object oriented programming for us. But it's nothing more than sugar for prototypes and it's extremely important to understand how prototypes are working inside to be able to fix bugs or debug your transpiled code.

Also if you want to improve your programming skill I have lots of full courses regarding different web technologies.

📚 Source code of what we've done