Is it possible to inherit attributes and methods from one class to another?
As rabbits are animals, 3 class should be based on 9, have access to animal methods, so that rabbits can do what “generic” animals can do. Show
The syntax to extend another class is: 5.Let’s create 2 that inherits from 9:
Object of 3 class have access both to 3 methods, such as 0, and also to 9 methods, such as 2.Internally, 3 keyword works using the good old prototype mechanics. It sets 4 to 5. So, if a method is not found in 6, JavaScript takes it from 5.For instance, to find 8 method, the engine checks (bottom-up on the picture):
As we can recall from the chapter Native prototypes, JavaScript itself uses prototypal inheritance for built-in objects. E.g. 7 is 8. That’s why dates have access to generic object methods.Any expression is allowed after Class syntax allows to specify not just a class, but any expression after 3.For instance, a function call that generates the parent class:
Here 1 inherits from the result of 2.That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them. Overriding a methodNow let’s move forward and override a method. By default, all methods that are not specified in 2 are taken directly “as is” from 4.But if we specify our own method in 3, such as 6 then it will be used instead:
Usually, however, 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 7 keyword for that.
For instance, let our rabbit autohide when stopped:
Now 3 has the 1 method that calls the parent 2 in the process.Arrow functions have no As was mentioned in the chapter Arrow functions revisited, arrow functions do not have 3.If accessed, it’s taken from the outer function. For instance:
The 3 in the arrow function is the same as in 6, so it works as intended. If we specified a “regular” function here, there would be an error:
Overriding constructorWith constructors it gets a little bit tricky. Until now, 3 did not have its own 8.According to the specification, if a class extends another class and has no 8, then the following “empty” 8 is generated:
As we can see, it basically calls the parent 8 passing it all the arguments. That happens if we don’t write a constructor of our own.Now let’s add a custom constructor to 3. It will specify the 3 in addition to 4:
Whoops! We’ve got an error. Now we can’t create rabbits. What went wrong? The short answer is:
…But why? What’s going on here? Indeed, the requirement seems strange. Of course, there’s an explanation. Let’s get into details, so you’ll really understand what’s going on. In JavaScript, there’s a distinction between a constructor function of an inheriting class (so-called “derived constructor”) and other functions. A derived constructor has a special internal property 7. That’s a special internal label.That label affects its behavior with 8.
So a derived constructor must call 3 in order to execute its parent (base) constructor, otherwise the object for 6 won’t be created. And we’ll get an error.For the 3 constructor to work, it needs to call 4 before using 6, like here:
Overriding class fields: a tricky noteAdvanced note This note assumes you have a certain experience with classes, maybe in other programming languages. It provides better insight into the language and also explains the behavior that might be a source of bugs (but not very often). If you find it difficult to understand, just go on, continue reading, then return to it some time later. We can override not only methods, but also class fields. Although, there’s a tricky behavior when we access an overridden field in parent constructor, quite different from most other programming languages. Consider this example: 0Here, class 3 extends 9 and overrides the 4 field with its own value.There’s no own constructor in 3, so 9 constructor is called.What’s interesting is that in both cases: 1 and 2, the 3 in the line 4 shows 0.In other words, the parent constructor always uses its own field value, not the overridden one. What’s odd about it? If it’s not clear yet, please compare with methods. Here’s the same code, but instead of 6 field we call 7 method: 1Please note: now the output is different. And that’s what we naturally expect. When the parent constructor is called in the derived class, it uses the overridden method. …But for class fields it’s not so. As said, the parent constructor always uses the parent field. Why is there a difference? Well, the reason is the field initialization order. The class field is initialized:
In our case, 3 is the derived class. There’s no 00 in it. As said previously, that’s the same as if there was an empty constructor with only 01.So, 2 calls 4, thus executing the parent constructor, and (per the rule for derived classes) only after that its class fields are initialized. At the time of the parent constructor execution, there are no 3 class fields yet, that’s why 9 fields are used.This subtle difference between fields and methods is specific to JavaScript. Luckily, this behavior only reveals itself if an overridden field is used in the parent constructor. Then it may be difficult to understand what’s going on, so we’re explaining it here. If it becomes a problem, one can fix it by using methods or getters/setters instead of fields. Super: internals, [[HomeObject]]Advanced information If you’re reading the tutorial for the first time – this section may be skipped. It’s about the internal mechanisms behind inheritance and 3.Let’s get a little deeper under the hood of 3. We’ll see some interesting things along the way.First to say, from all that we’ve learned till now, it’s impossible for 3 to work at all!Yeah, indeed, let’s ask ourselves, how it should technically work? When an object method runs, it gets the current object as 6. If we call 10 then, the engine needs to get the 11 from the prototype of the current object. But how?The task may seem simple, but it isn’t. The engine knows the current object 6, so it could get the parent 11 as 14. Unfortunately, such a “naive” solution won’t work.Let’s demonstrate the problem. Without classes, using plain objects for the sake of simplicity. You may skip this part and go below to the 15 subsection if you don’t want to know the details. That won’t harm. Or read on if you’re interested in understanding things in-depth.In the example below, 16. Now let’s try: in 17 we’ll call 18, using 19: 2At the line 4 we take 21 from the prototype ( 0) and call it in the context of the current object. Please note that 23 is important here, because a simple 24 would execute parent 21 in the context of the prototype, not the current object.And in the code above it actually works as intended: we have the correct 3.Now let’s add one more object to the chain. We’ll see how things break: 3The code doesn’t work anymore! We can see the error trying to call 27.It may be not that obvious, but if we trace 27 call, then we can see why. In both lines 4 and 30 the value of 6 is the current object ( 32). That’s essential: all object methods get the current object as 6, not a prototype or something.So, in both lines 4 and 30 the value of 19 is exactly the same: 9. They both call 38 without going up the chain in the endless loop.Here’s the picture of what happens:
The problem can’t be solved by using 6 alone.class Rabbit extends Animal { hide() { alert(`${this.name} hides!`); } } let rabbit = new Rabbit("White Rabbit"); rabbit.run(5); // White Rabbit runs with speed 5. rabbit.hide(); // White Rabbit hides!15To provide the solution, JavaScript adds one more special internal property for functions: 15.When a function is specified as a class or object method, its 15 property becomes that object.Then 3 uses it to resolve the parent prototype and its methods.Let’s see how it works, first with plain objects: 6It works as intended, due to 15 mechanics. A method, such as 55, knows its 15 and takes the parent method from its prototype. Without any use of 6.Methods are not “free”As we’ve known before, generally functions are “free”, not bound to objects in JavaScript. So they can be copied between objects and called with another 6.The very existence of 15 violates that principle, because methods remember their objects. 15 can’t be changed, so this bond is forever.The only place in the language where 15 is used – is 3. So, if a method does not use 3, then we can still consider it free and copy between objects. But with 3 things may go wrong.Here’s the demo of a wrong 3 result after copying: 7A call to 66 shows “I’m an animal”. Definitely wrong.The reason is simple:
Here’s the diagram of what happens: Methods, not function properties 15 is defined for methods both in classes and in plain objects. But for objects, methods must be specified exactly as 79, not as 80.The difference may be non-essential for us, but it’s important for JavaScript. In the example below a non-method syntax is used for comparison. 15 property is not set and the inheritance doesn’t work:
Can a class inherit from another class?In the Java language, classes can be derived from other classes, thereby inheriting fields and methods from those classes. Definitions: A class that is derived from another class is called a subclass (also a derived class, extended class, or child class).
What is the method of inheriting the variable of one class to any other class?Inheritance can be defined as the process where one class acquires the properties (methods and fields) of another. With the use of inheritance the information is made manageable in a hierarchical order.
Is a class from which attributes and methods can be inherited?The class that inherits the properties/behavior of some other class is called the subclass while the class from whom properties/attributes are being inherited is called the superclass.
|