Basic explanation of JavaScript inheritance (prototype chain, borrow constructor, hybrid mode, original type inheritance, parasitic inheritance, and parasitic combined inheritance) and javascript Constructor
It's a long time to explain JavaScript inheritance. If you don't talk nonsense, go to the topic.
Now that you want to learn about inheritance, it proves that you have a certain understanding of JavaScript object-oriented. For more information, see basic introduction to object-oriented JS, factory mode, constructor mode, prototype mode, hybrid mode, and dynamic prototype mode. Next we will talk about the methods used to inherit JavaScript.
Prototype chain
The simplest way to implement inheritance in JavaScript is to use the prototype chain to direct the prototype of the Child type to the parent type instance, that is, "Child type. prototype = new parent type (); ", the implementation method is as follows:
// Create the constructor function SuperType () {this. name = ['wuyuchang', 'jack', 'Tim']; this. property = true;} // Add method SuperType for parent type. prototype. getSuerperValue = function () {return this. property;} // create the constructor SubType () {this. test = ['h1 ', 'h2', 'h3 ', 'h4']; this. subproperty = false;} // The key step to implement inheritance. The prototype of the Child type points to the SubType of the parent type instance. prototype = new SuperType (); // Add a method to the child type here. It must be inherited after implementation. Otherwise, the method is null when the pointer is directed to the parent type instance. prototype. getSubValue = function () {return this. subproperty;}/* example of the test code */var instance1 = new SubType (); instance1.name. push ('wyc'); instance1.test. push ('h5'); alert (instance1.getSuerperValue (); // truealert (instance1.getSubValue (); // falsealert (instance1.name); // wuyuchang, Jack, Tim, wycalert (instance1.test); // h1, h2, h3, h4, h5var instance2 = new SubType (); alert (instance2.name); // wuyuchang, Jack, Tim, wycalert (instance2.test); // h1, h2, h3, h4
We can see that the above Code is a simple inheritance implemented through the prototype chain, but there are still some problems in the test code example. I believe that after reading my blog post "basic introduction to object oriented JS, factory mode, constructor mode, prototype mode, hybrid mode, and dynamic prototype mode", my shoes will surely understand the existence of the prototype chain code.The first problem is that the prototype of the Child type is the parent type instance, that is, the attributes of the parent type contained in the child Type prototype, as a result, the prototype property of the reference type value will be shared by all instances.. The above code instance1.name. push ('wyc'); can prove the existence of this problem. The second problem of prototype chain is:When creating a child-type instance, parameters cannot be passed to a super-Type constructor.. Therefore, in actual development, prototype chains are rarely used independently.
Borrow Constructor
To solve the two problems in the prototype chain, developers began to use a technology called borrow constructor to solve the problems in the prototype chain. The implementation of this technology is quite simple. You only need to call the parent Type constructor within the child Type constructor. Don't forget, a function is just an object that executes code in a specific environment, so you canUse the apply () or call () method to execute the constructor.. The Code is as follows:
// Create the constructor function SuperType (name) {this. name = name; this. color = ['pink ', 'yellow']; this. property = true; this. testFun = function () {alert ('HTTP: // tools.jb51.net/');} // Add method SuperType for parent type. prototype. getSuerperValue = function () {return this. property;} // create the constructor SubType (name) {SuperType. call (this, name); this. test = ['h1 ', 'h2', 'h3 ', 'h4']; this. subproperty = false;} // Add a method to the child type here. It must be inherited after implementation. Otherwise, the method is null when the pointer is directed to the parent type instance. prototype. getSubValue = function () {return this. subproperty;}/* example of the test code */var instance1 = new SubType (['wuyuchang', 'jack', 'Nick ']); instance1.name. push ('hello'); instance1.test. push ('h5'); instance1.color. push ('Blue '); instance1.testFun (); // http://tools.jb51.net/alert (instance1.name); // wuyuchang, Jack, Nick, hello // alert (instance1.getSuerperValue ()); // error alert (instance1.test); // h1, h2, h3, h4, h5 alert (instance1.getSubValue (); // false alert (instance1.color); // pink, yellow, bluevar instance2 = new SubType ('wyc'); instance2.testFun (); // http://tools.jb51.net/alert (instance2.name); // wyc // alert (instance2.getSuerperValue ()); // error alert (instance2.test); // h1, h2, h3, h4alert (instance2.getSubValue (); // falsealert (instance2.color); // pink, yellow
We can see that the constructor of SubType in the code above calls the parent type "SuperType. call (this, name); "to realize the inheritance of attributes, you can also pass parameters for the parent type when creating an instance for the child type, but a new problem arises. As you can see, I defined a method in the parent constructor: testFun, and defined a method in the parent Type prototype: getSuperValue. HoweverAfter the child type is instantiated, the method defined in the parent type cannot be called.GetSuperValue, which can only call the constructor method of the parent type: testFun. This is the same as using only the constructor mode in the creation object, so that the function is not reusable. Considering these issues, the techniques for borrowing constructors are rarely used independently.
Combination inheritance (prototype chain + borrow constructor)
As the name implies, combined inheritance is a mode that combines the advantages of prototype chain and borrow constructor. The implementation is also very simple. Since it is a combination, of course it combines the advantages of both parties, that isThe prototype chain inherits attributes from the constructor.. The Code is as follows:
// Create the constructor function SuperType (name) {this. name = name; this. color = ['pink ', 'yellow']; this. property = true; this. testFun = function () {alert ('HTTP: // tools.jb51.net/');} // Add method SuperType for parent type. prototype. getSuerperValue = function () {return this. property;} // create the constructor SubType (name) {SuperType. call (this, name); this. test = ['h1 ', 'h2', 'h3 ', 'h4']; this. subproperty = false;} SubType. prototype = new SuperType (); // Add a method to the child type here. It must be inherited after implementation. Otherwise, the method is null when the pointer is directed to the parent type instance. prototype. getSubValue = function () {return this. subproperty;}/* example of the test code */var instance1 = new SubType (['wuyuchang', 'jack', 'Nick ']); instance1.name. push ('hello'); instance1.test. push ('h5'); instance1.color. push ('Blue '); instance1.testFun (); // http://tools.jb51.net/alert (instance1.name); // wuyuchang, Jack, Nick, helloalert (instance1.getSuerperValue (); // truealert (instance1.test ); // h1, h2, h3, h4, h5 alert (instance1.getSubValue (); // false alert (instance1.color); // pink, yellow, bluevar instance2 = new SubType ('wyc'); instance2.testFun (); // http://tools.jb51.net/alert (instance2.name); // wyc alert (); // truealert (instance2.test ); // h1, h2, h3, h4alert (instance2.getSubValue (); // falsealert (instance2.color); // pink, yellow
The above Code uses SuperType. call (this, name); to inherit the attributes of the parent type, and uses SubType. prototype = new SuperType (); to inherit the methods of the parent type. The above code easily solves the problems encountered by the prototype chain and borrow constructor, and becomes the most common method for inheriting instances in JavaScript. However, the hybrid mode does not have any disadvantages. We can see that the property of the parent type is actually inherited when the method is inherited in the above Code, but the reference type is shared at this time, therefore, the sub-Type constructor calls the parent constructor to inherit the attributes of the parent type and overwrite the attributes inherited in the prototype, it is obviously unnecessary to call the constructor twice in this way, but what can be done? To solve this problem, first look at the following two modes.
Original Type inheritance
The implementation method of the original type inheritance is different from that of the ordinary inheritance. The original type inheritance does not use constructors in a strict sense. Instead, the prototype can be used to create new objects based on existing objects, you do not need to create a custom type. The Code is as follows:
function object(o) { function F() {} F.prototype = o; return new F();}
Sample Code:
/* Original type inheritance */function object (o) {function F () {} F. prototype = o; return new F ();} var person = {name: 'wuyuchang', friends: ['wyc', 'nicholas ', 'Tim']} var anotherPerson = object (person); anotherPerson. name = 'greg '; anotherPerson. friends. push ('bob'); var anotherPerson2 = object (person); anotherPerson2.name = 'jack'; anotherPerson2.friends. push ('Rose '); alert (person. friends); // wyc, Nicolas, Tim, Bob, Rose
Parasitic inheritance
/* Parasitic inheritance */function createAnother (original) {var clone = object (original); clone. sayHi = function () {alert ('Hi');} return clone ;}
Example:
/* Original type inheritance */function object (o) {function F () {} F. prototype = o; return new F ();}/* parasitic inheritance */function createAnother (original) {var clone = object (original); clone. sayHi = function () {alert ('Hi');} return clone;} var person = {name: 'wuyuchang', friends: ['wyc', 'nicholas ', 'Rose ']} var anotherPerson = createAnother (person); anotherPerson. sayHi ();
Parasitic combined inheritance
We have mentioned the disadvantages of implementing inheritance in the combined Crip mode. Now we can solve the disadvantages. The implementation idea is that for the constructor to inherit attributes, and the prototype chain to inherit in the mixed form, that is, you do not need to instantiate the parent Type constructor when inheriting the method. The Code is as follows:
Function object (o) {function F () {} F. prototype = o; return new F ();}/* parasitic combined inheritance */function inheritPrototype (subType, superType) {var prototype = object (superType. prototype); prototype. constructor = subType; subType. prototype = prototype ;}
During use, you only need to replace "SubType. prototype = new SuperType ();" in the combination mode with inheritPrototype (subType, superType. The high efficiency of parasitic combined inheritance is that it only calls the parent Type constructor once, avoiding unnecessary or unnecessary attributes. At the same time, the prototype chain can remain unchanged, so instanceof and isPrototypeof () can be used normally (). This is also the most ideal inheritance method currently, and is also transforming to this mode. (YUI also uses this mode .)
This blog reference JavaScript advanced programming version 3rd, the code is rewritten, more specific, and added annotations to make everyone easier to understand. For example, if you have unique insights on JS inheritance, please feel free to reply to your comments for your reference!
In the prototype Inheritance Method of JavaScript, why can't the subclass PASS Parameters when calling the constructor of the parent class?
I used to encounter this problem when I was reading a book. I found a lot of information without a clear explanation.
In my opinion, it is not syntactically impossible to pass parameters to constructors, but it does not comply with the object-oriented programming rules: the object (Instance) is the property owner.
If the property is assigned a value when defining a subclass, the object instance cannot change its own property. In this way, the class has attributes, rather than the object has attributes.
For example, subclass Children inherits the parent class Parents and Parents constructor:
Function Parents (name) {this. name = name ;}
Use the prototype chain and pass parameters to the parent class constructor:
Children. prototype = new Parents ("Hello ");
At this time, the Children class has the name = "Hello" attribute, and the Children class instance objects c1, c2, c3 and so on can only be forced to accept this name attribute. Children is the owner of "Hello", but c1, c2, and c3 are not!
Therefore, the meaning of object-oriented programming is completely lost. Therefore, it is stipulated in the prototype chain inheritance mode that parameters cannot be transmitted to the parent class constructor. For this reason, the prototype chain inheritance method is not practical.
JS class inheritance is different from prototype inheritance
Similar to java inheritance, class inheritance has a simple idea: calling a super-Type constructor within a sub-Type constructor.
The original type inheritance creates a new object with an existing object, and points the prototype of the subclass to the parent class, which is equivalent to adding the prototype chain of the parent class.
The code below is not strictly a class inheritance. According to Nicholas C. Zakas, this should be called a combination inheritance. It calls parent2 () twice (). The first time is child2.prototype = new parent2 ('param'); child2 will get two attributes: param and getParam (). They are all attributes of parent2, but they are in the child2 prototype. The second is parent2.call (this, cparam); this time, the instance attributes param and getParam () are created on the new object (). Therefore, these two attributes shield the two attributes with the same name in the prototype. What is the benefit of this? When building a child3, you inherit the parent2 () Attribute and can define your own attributes. At the same time, his length is different from his brother, but he has the same "lineage (using the parent method )".
Click it to continue.