JavaScript is a prototype-based object language, not something we are familiar with, like the C # language class-based object-oriented language. In the previous article, we've covered the creation of object definitions in JavaScript. Let's take a look at the inheritance of JavaScript objects. We use an example to introduce several methods of object inheritance implementation.
Inheritance of constructors
In the previous article, we introduced the methods of function objects call and apply, which are used to invoke a function and replace the method in the method that is called by the object specified in the methods. It is for this reason that we can consider calling the function fruit in Apple's constructor to have the Apple object replace this in fruit, so that the Apple object has a fruit contain method, Apple's own attribute color can also be used without having to define it in its own constructor.
functionApple (variety, color) {Fruit.call ( This, color); This. Variety =variety; This. whatvariety =function() {Console.log ("It is" + This. Variety + "."); }}varMyapple =NewApple ("Fuji", "Red"); Myapple.whatcolor (); //This fruit color is red.Myapple.contain ();//which vitamins it contains.Myapple.whatvariety ();//It is Red Fuji.
You can see that the Apply object has properties and methods of the fruit object in addition to the properties of its own province. But if the fruit object prototype has a property type defined as follows
Fruit.prototype.type = "Fruit";
If we use the above method to inherit, we will find that the attribute type is not defined in Myapple.
Alert (typeof// undefined
Prototype (prototype) mode inheritance
We know that each object has a prototype, which is also a feature of JavaScript.
If you let Apple's prototype point to an instance of the Fruilt object, Apple objects can have all the properties and methods of fruit.
functionApple (variety, color) {Fruit.call ( This, color); This. Variety =variety; This. whatvariety =function() {Console.log ("It is" + This. Variety + "."); }} Apple.prototype=NewFruit (); Apple.prototype.constructor=Apple; varMyapple =NewApple ("Fuji", "Red"); Myapple.whatcolor (); //This fruit color is red.Myapple.contain ();//which vitamins it contains.alert (Myapple.type);//Fruit
Each object prototype has a constructor property that points to the object's constructor, and each object instance also has a constructor property, which calls the prototype's constructor by default. If there is no Apple.prototype.constructor = Apple , then it will be because Apple.prototype = new Fruit (); Let Apple.prototype.constructor point to fruit, which obviously leads to an inheritance chain disorder, so we have to manually correct the Apple.prototype object's constructor value to Apple. This is an important point to be sure to follow when programming. We should follow this in JavaScript, that is, if you replace the prototype object, you must refer to the attribute constructor back to the original constructor (the object's original constructor).
There is no problem with this approach, but there is one drawback: when you define a new object, you need to create an instance of the inherited object, sometimes in a way that consumes a certain amount of memory and is inefficient. If you assign Fruit.prototype to Apple.prototype, you don't need to create an object instance.
functionFruit (color) { This. color =color; This. Whatcolor =function() {Console.log ("This fruit color is" + This. Color + "."); } This. contain =function() {Console.log ("Which vitamins it contains.")}} Fruit.prototype.type= "Fruit"; functionApple (variety, color) {Fruit.call ( This, color); This. Variety =variety; This. whatvariety =function() {Console.log ("It is" + This. Variety + "."); }} Apple.prototype= Fruit.prototype;//The constructor of Apple be Fruit.Apple.prototype.constructor = Apple;//assign the constructor back to itself varMyapple =NewApple ("Fuji", "Red"); Alert (typeof(Myapple.type));//Fruit
This way, the Apple object inherits all the properties and methods of the parent object fruit, and is more efficient and saves memory. But the disadvantage is that the prototype of the Apple object and the prototype of the Fruilt object are the same object, and if we modify one of them, it will inevitably affect the other.
So code Apple.prototype.constructor = Apple; Although it fixes the problem with the Apple constructor, there is a problem with the constructor of the fruit object.
// true
In combination with the pros and cons of the two approaches of prototype pattern inheritance, we have another way of inheriting from each other.
Inherit with an empty object as an intermediary
functionFruit (color) { This. color =color; This. Whatcolor =function() {Console.log ("This fruit color is" + This. Color + "."); } This. contain =function() {Console.log ("Which vitamins it contains.")}} Fruit.prototype.type= "Fruit"; functionApple (variety, color) {Fruit.call ( This, color); This. Variety =variety; This. whatvariety =function() {Console.log ("It is" + This. Variety + "."); } } functionEmpty () {} Empty.prototype=Fruit.prototype; Apple.prototype=NewEmpty (); Apple.prototype.constructor= Apple;
The empty object is a null object and hardly accounts for memory, and if modifying apple.prototype does not affect the fruit Prototye object. In some JavaScript libraries, the above method is usually encapsulated as a function:
function Extend (child, parent) { varfunction () {}; = Parent.prototype; New e (); = Child ;}
When you use this approach, don't forget to call the parent object's constructor in the child object's constructor to initialize the properties and methods in the parent object, so that the parent object property is the default value for each newly created child object instance. If the above example is removed from the
Fruit.call (this, color);
After
var New Apple ("HFS", "Red"); // This fruit color is undefined.
Although we passed the "red" value when we created the Apple instance, it was undefined. The problem arises in Apple.prototype = new Empty () , when there is no color attribute defined in Apple, so even if a value is passed into the constructor, the color property is not defined. After adding the code called by the parent object constructor, let the child object have the methods and properties of the parent object, and initialize them with the values passed in.
Copy inheritance
Next we introduce another way to implement inheritance purely using the "copy" method. Simply put, by copying all the properties and methods of the parent object instance into the child object to implement the inheritance.
functionFruit (color) { This. color =color; This. Whatcolor =function() {Console.log ("This fruit color is" + This. Color + "."); } This. contain =function() {Console.log ("Which vitamins it contains.")}} Fruit.prototype.type= "Fruit"; Function.prototype.extendEx=function(parent) { for(varPinchparent) { This. prototype[p] =Parent[p]; } } functionApple (variety, color) {Fruit.call ( This, color); This. Variety =variety; This. whatvariety =function() {Console.log ("It is" + This. Variety + "."); }} apple.extendex (NewFruit ()); varMyapple =NewApple ("HFS", "Red"); Myapple.whatcolor (); //This fruit color is red.Myapple.contain ();//which vitamins it contains.alert (Myapple.type);//Fruit