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 some features of JavaScript that should be used in TypeScript projects, including object inheritance.
JavaScript Object Inheritance
JavaScript objects can have a link to another object.
The object is called the prototype.
Objects inherit properties and methods from the prototype.
This allows us to implement complex features to be defined once and used consistently.
When we create an object using the literal syntax, then its prototype is Object
.
Object
provides some basic features they inherit like the toString
method that returns the string representation of an object.
For instance, if we have the following object:
const obj = {
foo: 1,
bar: "baz"
};
console.log(obj.toString());
If we define obj
and run:
console.log(obj.toString());
We get [object Object]
logged.
That’s what the default toString
method does in the Object
‘s prototype.
Object’s Prototype
Object
is the prototype for most objects.
We can also use some methods directly.
There’s the getPrototypeOf
, setPrototypeOf
, and getOwnPropertyNames
methods.
getPrototypeOf
returns the prototype of an object.
For instance, we can write:
const proto = {};
const obj = Object.create(proto);
let objPrototype = Object.getPrototypeOf(obj);
Then we get that objPrototype
is Object
.
proto
is the prototype of obj
since we passed it into Object.create
.
Creating Custom Prototypes
Also, we can use the setPrototypeOf
method to set the prototype of an existing object.
For instance, we can write:
const proto = {};
const obj = {
foo: 1
};
Object.setPrototypeOf(obj, proto);
const objProto = Object.getPrototypeOf(obj);
console.log(proto === objProto);
The code above has 2 objects, obj
and proto
.
Then we call setPrototype
with obj
and proto
to set proto
as the prototype of obj
.
In the last line, we check is proto
refers to the same object as the prototype object returned from getPrototypeOf
.
Console log returns true
so we know that the prototype of obj
is actually proto
.
Constructor Functions
A constructor function is used to create a new object, configure its properties, and assign its prototype.
For instance, we can create one by writing:
let Dog = function(name, breed) {
this.name = name;
this.breed = breed;
};
Dog.prototype.toString = function() {
return `name: ${this.name}, breed: ${this.breed}`;
};
We have a Dog
constructor function with the name
and breed
fields.
Then we created an instance method called toString
to return the string representation of a Dog
instance.
Then we can create a Dog
instance and call toString
as follows:
console.log(new Dog('joe', 'labrador').toString());
And we get:
'name: joe, breed: labrador'
in the console log output.
We invoked our constructor function with the new
keyword.
The arguments are passed in and set as properties of this
in the constructor function.
The constructor function configures the object own properties using this
, which is set to a new object.
The prototype of the object returned by the constructor has its __proto__
set to Dog.prototype
.
So toString
is from the Dog
instance’s prototype
property.
Chaining Constructor Functions
We can chain the constrictor functions of more than one function by writing:
const Animal = function(name) {
this.name = name;
};
Animal.prototype.toString = function() {
return `toString: name: ${this.name}`;
};
const Dog = function(name, breed) {
Animal.call(this, name);
this.breed = breed;
};
Object.setPrototypeOf(Dog.prototype, Animal.prototype);
Dog.prototype.bark = function() {
return "woof";
};
const dog = new Dog("joe", "labrador");
console.log(dog.toString());
console.log(dog.bark());
We have a parent Animal
constructor which has a toString
method in its prototype.
Then we added a Dog
constructor, which inherits from the Animal
constructor.
In the Dog
constructor, we call the call
method on Animal
to call the parent Animal
constructor but with this
set to the Dog
constructor.
Dog
inherits from Animal
by calling setPrototypeOf
with the child constructor in the first argument and the parent as the 2nd.
Then we add another method to the prototype called bark
to Dog
‘s prototype, so we can only be called that on a Dog
instance.
toString
is available to both Dog
and Animal
.
Conclusion
JavaScript’s inheritance system isn’t like the other object-oriented language’s inheritance system.
JavaScript has constructor functions and prototypes rather than classes.
Objects can inherit from other objects directly. Constructors can inherit from other constructors.