Before you start tinkering with code, you should understand the purpose and benefits of using inheritance. Generally speaking, when designing classes, we hope to reduce repetitive code and try to weaken the coupling between classes. It is difficult to balance both. We need to decide what method we should take based on specific conditions and circumstances. According to our understanding of inheritance in object-oriented languages, inheritance will bring direct strong coupling of classes, but due to its unique flexibility, js can design codes with strong coupling and weak coupling, high efficiency and low efficiency. What to use depends on the situation.
The following are three ways to implement inheritance in js: class inheritance, prototypal inheritance, and metaclasses. Class inheritance will be briefly described here first, and the last two will be briefly described later. Please pay more attention and guidance, thank you.
Classic inheritance.
The implementation of js class inheritance relies on the prototype chain. What is a prototype chain? Objects in js have an attribute called prototype. This attribute returns a reference to the object type and is used to provide a set of basic functions of the object's class.
It seems that I have an impression of prototype. By the way, we often use code like this.
We put the basic functions of the class in the prototype attribute, indicating that the reference to the Person object has XXX functions.
After understanding prototypes, you need to understand what a prototype chain is. When accessing a member (property or method) of an object, if this member is not found in the current object, js will search for it in the object pointed to by the prototype attribute. If it is not found yet, it will continue to the next-level prototype. Search the pointed object until it is found. If not found, undefined will be returned.
So what hints does the prototype chain give us? It is easy to think that the prototype chain means that for one class to inherit another class, you only need to set the prototype of the subclass to point to an instance of the parent class. This binds the members of the parent class to the child class, because if a member cannot be found in the child class, it will be searched in the parent class. (The wording in the above two paragraphs is not rigorous, just describing it in easy-to-understand terms)
Next we need a Chinese class, which needs to inherit the name and getName members of the Person class.
The inheritance relationship is established, we call it like this
So class inheritance is completed. Is it really completed? Use firebug to set a breakpoint in alert, and you will find that the original Person.prototype has been modified and the getNation method has been added.
This is because in the above code Chinese.prototype = Person.prototype; this is a reference type. Modifying Chinese also modifies Person. This in itself is intolerable and creates strong coupling between classes. This is not the effect we want.
We can create a new object or instantiate an instance to weaken coupling.
What is the difference between these two methods. In the second type, an empty function F is added. This can avoid creating an instance of the parent class, because the parent class may be relatively large, and the constructor of the parent class will have some side effects or perform a large amount of calculations. Task. Therefore, we strongly recommend the second method.
This is it, it’s over, not yet! There is an attribute constructor under the object's prototype attribute, which holds a reference to the function that constructs a specific object instance. According to this statement Chiese.prototype.constructor should be equal to Chinese, but it is not.
Recall that when setting up the prototype chain of Chiese, we overwrote Chiese.prototype with Person.prototype. So the Chiese.prototype.constructor at this time is Person. We also need to add the following code
Organize all the codes as follows
If you can put the inherited code in a function to facilitate code reuse, the final code is organized as follows
Revised after publishing:
Under the comments on the first floor, I have new views on the extend function. Two methods were proposed before when discussing how to set up the prototype chain
Although the second method reduces the need to call the constructor of the parent class, Person.call(this,name) was used when designing the Chinese class; this is also equivalent to calling the constructor of the parent class.
However, using the first method can reduce the need to write Person.call(this,name); in Chinese. This part of the code is often forgotten in subclasses. You might as well put this functional code in extend. Just write
Chinese.prototype = new Person(); also achieves the same purpose: the coupling is not strong.
But the forgotten thing is that Chinese.prototype = new Person(); is written correctly. The answer is no! Obviously new Person() needs to pass a name parameter. We can't do this part of the work in the extend function, so we have to call the constructor of the parent class in the Chinese class. This is also in line with object-oriented thinking.
So, it is still highly recommended to use the second method.
This is the first time I write a technical article like this. I basically develop it according to my own ideas. It is inevitable that there will be some places that have not been taken into consideration and unclear explanations. I hope to leave a message for feedback, thank you.