This commit is contained in:
Ilya Kantor 2019-10-11 10:00:53 +03:00
parent c3fadb7dc1
commit c9eea4d0bf
3 changed files with 22 additions and 52 deletions

View file

@ -1,9 +1,13 @@
# Class inheritance
Let's say we have two classes.
Class inheritance is a way for one class to extend another class.
`Animal`:
So we can create new functionality on top of the existing.
## The "extends" keyword
Let's say with have class `Animal`:
```js
class Animal {
@ -24,52 +28,19 @@ class Animal {
let animal = new Animal("My animal");
```
Here's how we can represent `animal` object and `Animal` class graphically:
![](rabbit-animal-independent-animal.svg)
...And we would like to create another `class Rabbit`.
...And `Rabbit`:
As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods.
The syntax to extend another class is: `class Child extends Parent`.
Let's create `class Rabbit` that inherits from `Animal`:
```js
class Rabbit {
constructor(name) {
this.name = name;
}
hide() {
alert(`${this.name} hides!`);
}
}
let rabbit = new Rabbit("My rabbit");
```
![](rabbit-animal-independent-rabbit.svg)
Right now they are fully independent.
But we'd want `Rabbit` to extend `Animal`. In other words, rabbits should be based on animals, have access to methods of `Animal` and extend them with its own methods.
To inherit from another class, we should specify `"extends"` and the parent class before the braces `{..}`.
Here `Rabbit` inherits from `Animal`:
```js run
class Animal {
constructor(name) {
this.speed = 0;
this.name = name;
}
run(speed) {
this.speed += speed;
alert(`${this.name} runs with speed ${this.speed}.`);
}
stop() {
this.speed = 0;
alert(`${this.name} stands still.`);
}
}
// Inherit from Animal by specifying "extends Animal"
*!*
class Rabbit extends Animal {
*/!*
@ -84,14 +55,12 @@ rabbit.run(5); // White Rabbit runs with speed 5.
rabbit.hide(); // White Rabbit hides!
```
Now the `Rabbit` code became a bit shorter, as it uses `Animal` constructor by default, and it also can `run`, as animals do.
Object of `Rabbit` class have access to both `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`.
Internally, `extends` keyword adds `[[Prototype]]` reference from `Rabbit.prototype` to `Animal.prototype`:
Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
![](animal-rabbit-extends.svg)
So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
As we can recall from the chapter <info:native-prototypes>, JavaScript uses prototypal inheritance for build-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`, so dates have generic object methods.
````smart header="Any expression is allowed after `extends`"
@ -119,19 +88,20 @@ That may be useful for advanced programming patterns when we use functions to ge
## Overriding a method
Now let's move forward and override a method. As of now, `Rabbit` inherits the `stop` method that sets `this.speed = 0` from `Animal`.
Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`.
If we specify our own `stop` in `Rabbit`, then it will be used instead:
But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead:
```js
class Rabbit extends Animal {
stop() {
// ...this will be used for rabbit.stop()
// ...now this will be used for rabbit.stop()
// instead of stop() from class Animal
}
}
```
...But usually we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
Usually we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
Classes provide `"super"` keyword for that.