TypeScript is a natural extension of JavaScript that’s used in many projects in place of JavaScript.
However, not everyone knows how it actually works.
In this article, we’ll look at accessing overridden prototype methods and the class syntax.
Accessing Overridden Prototype Methods
Even if we override methods in a constructor function that inherits from a parent constructor, we can still access the parent constructor’s implementation of the constructor.
For instance, if we have:
const Animal = function(name) {
this.name = name;
};
Animal.prototype.toString = function() {
return `name: ${this.name}`;
};
const Dog = function(name, breed) {
Animal.call(this, name);
this.breed = breed;
};
Object.setPrototypeOf(Dog.prototype, Animal.prototype);
Dog.prototype.toString = function() {
return `name: ${this.name}, breed: ${this.breed}`;
};
Then we can call the parent constructor’s method to replace part of Dog
‘s prototype’s toString
method by writing:
const Animal = function(name) {
this.name = name;
};
Animal.prototype.toString = function() {
return `name: ${this.name}`;
};
const Dog = function(name, breed) {
Animal.call(this, name);
this.breed = breed;
};
Object.setPrototypeOf(Dog.prototype, Animal.prototype);
Dog.prototype.toString = function() {
const name = Animal.prototype.toString.call(this, this.name);
return `${name}, breed: ${this.breed}`;
};
We reused the Animal.prototype
‘s toString
method to form part of Dog.prototype
‘s toString
method.
This way, we don’t have to repeat any code.
Defining Static Properties and Methods
We can define static methods and properties as properties on the function itself.
We can do that because functions are just ordinary objects.
For instance, we can write:
const Animal = function(name) {
this.name = name;
};
Animal.type = 'animal';
console.log(Animal.type);
Then we defined a static type
property on Animal
.
We can then access it by referencing Animal.type
.
JavaScript Classes
JavaScript class is a syntax that eases the transition from other popular programming languages.
However, behind the scenes, it’s just a combination of constructors and prototypes.
There are some differences between a JavaScript class and other class-based languages like Java.
All instance variables are public.
Also, we can return any object we want in the constructor
and we return that object when we invoke the class with new
.
Like constructor functions, it’s invoked with the new
keyword.
For instance, we can define a class by writing:
class Animal {
constructor(name) {
this.name = name;
}
toString() {
return `name: ${this.name}`;
}
}
We have an Animal
constructor that returns an Animal
instance, with the name
property and the toString
method.
Then if we create an Animal
instance by writing:
const animal = new Animal('joe');
If we look at the content of animal
, we see the name
property in animal
.
In the __proto__
property of it, we see the toString
method.
To create a subclass that inherits from a parent class, we use the extends
keyword.
For instance, we can write:
class Animal {
constructor(name) {
this.name = name;
}
toString() {
return `name: ${this.name}`;
}
}
class Dog extends Animal {}
We create a subclass of Animal
which inherits from the Animal
parent class.
Then when we write:
const dog = new Dog('joe');
and call toString
:
console.log(dog.toString());
We get:
name: joe
from the console log.
The toString
method is inherited from the Animal
class.
To call the parent constructor, we use the super
keyword.
And if we want to call a parent constructor’s methods, we use the same keyword followed by a dot plus the method name.
For instance, if we want to add constructor and a toString
method to Dog
, we can write:
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
toString() {
const name = super.toString();
return `${name} breed: ${this.breed}`;
}
}
Given the Animal
class we have before, we can call Animal
‘s toString
by writing calling super.toString();
.
We call the constructor
of the parent by using the super
keyword as we did in Dog
‘s constructor
.
The super
call must be before anything else in the constructor body.
The extends
keyword indicates that our Dog
class inherits members from the Animal
class.
So when we create a new Dog
instance by writing:
const dog = new Dog('joe', 'lab');
console.log(dog.toString());
and then call toString
on it, we get:
name: joe breed: lab
from the console log.
Conclusion
The class syntax makes transitioning from other object-oriented languages easier.
Also, it cleans up the constructor code by putting them in one neat package.
We can also call the parent constructor in a much cleaner fashion.