Portal
Supplement: prototype, prototype object, object prototype, prototype chain
Each constructor has a prototype prototype, which is just an object, so we often call it a prototype object. The role of prototype objects is to share
Each instance object also has a property called__ proto__ Or [[prototype]], because it is on the object, it is called "object prototype". Its purpose is to "point to the prototype object of the constructor"
When calling the properties and methods of an Object, js will first find out whether the current Object has the property. If not, it will continue to find the prototype (prototype Object). If the property has not been found, it will continue to find it until it reaches the Object. If it still does not find it, it will return undefined. This process is the prototype chain
Five methods of "inheritance" between objects.
Introduction: for example, there is now a constructor for an "animal" object.
function Animal(){ this.species = "animal"; } Animal.prototype.hair = "Yellow hair"; Animal.prototype.fly = function () { console.log("You sand sculpture wants to fly better!") }
There is also a constructor for the "cat" object.
function Cat(name,color){ this.name = name; this.color = color; }
How can the cat inherit the animal?
1, Constructor binding
Introduction: the first method is also the simplest method. Use the call or apply method to bind the constructor of the parent object to the child object, that is, add a line in the constructor of the child object:
function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; } var cat1 = new Cat("Big hair","yellow"); alert(cat1.species); // animal // Try calling the prototype object method of Animal console.log(bird1.hair); //undefined
Disadvantages: you cannot inherit the properties and methods of the Animal prototype object
2, prototype mode
Introduction: the second method is more common, using the prototype attribute. If the prototype object of "cat" points to an instance of Animal, all instances of "cat" can inherit Animal.
Cat.prototype = new Animal(); Cat.prototype.constructor = Cat; var cat1 = new Cat("Big hair","yellow"); alert(cat1.species); // animal
In the first line of the code, we point the prototype object of Cat to an instance of Animal.
Cat.prototype = new Animal();
It is equivalent to completely deleting the original value of the prototype object and giving it a new value. But what does the second line mean?
Cat.prototype.constructor = Cat;
It turns out that any prototype object has a constructor attribute that points to its constructor. If there is no "Cat.prototype = new Animal();" This line, Cat prototype. Constructor refers to Cat; After adding this line, Cat prototype. Constructor points to Animal.
alert(Cat.prototype.constructor == Animal); //true
More importantly, each instance also has a constructor attribute, which calls the constructor attribute of the prototype object by default.
alert(cat1.constructor == Cat.prototype.constructor); // true
Therefore, when running "Cat.prototype = new Animal();" After this line, CAT1 Constructor also points to Animal!
alert(cat1.constructor == Animal); // true
This will obviously lead to the disorder of the inheritance chain (cat1 is clearly generated by the constructor Cat), so we must manually correct it and change the constructor value of the Cat.prototype object to Cat. This is what the second line means.
This is a very important point, which must be observed when programming. This is followed below, that is, if the prototype object is replaced,
o.prototype = {};
Then, the next step must be to add the constructor attribute to the new prototype object and point this attribute back to the original constructor.
o.prototype.constructor = o;
3, Directly inherit prototype
Introduction: the third method is the improvement of the second method. Because in the Animal object, invariant attributes can be written directly to Animal prototype. Therefore, we can also let Cat() skip Animal() and directly inherit Animal prototype.
Now, let's rewrite the Animal object:
function Animal(){ } Animal.prototype.species = "animal";
If this method is still adopted
function Animal(){
this.species = "animals";
}
Cat is an attribute that cannot be inherited to species
console.log(cat1.species); // undefined
Then, connect the prototype object of Cat to the prototype object of Animal, and then complete the inheritance.
Cat.prototype = Animal.prototype; Cat.prototype.constructor = Cat; var cat1 = new Cat("Big hair","yellow"); alert(cat1.species); // animal
Compared with the previous method, this method has the advantages of high efficiency (no need to execute and create an instance of Animal) and memory saving. The disadvantage is that Cat.prototype and Animal.prototype now point to the same object, so any modification to Cat.prototype will be reflected in Animal.prototype.
Therefore, the above code is actually problematic. Look at the second line
Cat.prototype.constructor = Cat;
This sentence actually puts animal The constructor attribute of the prototype object has also been changed!
alert(Animal.prototype.constructor); // Cat
4, Using empty objects as mediators
Due to the above shortcomings of "direct inheritance prototype", there is a fourth method, using an empty object as an intermediary.
var F = function(){}; F.prototype = Animal.prototype; Cat.prototype = new F(); Cat.prototype.constructor = Cat;
**F is an empty object, so it hardly takes up memory** At this time, modifying the prototype object of Cat will not affect the prototype object of Animal.
alert(Animal.prototype.constructor); // Animal
We encapsulate the above method into a function for easy use.
function extend(Child, Parent) { var F = function(){}; // Point the prototype object of the empty object to the prototype object you want to inherit F.prototype = Parent.prototype; // Point the descendant prototype object to an instance object of an empty object Child.prototype = new F(); // Modify the constructor of children Child.prototype.constructor = Child; // See below Child.uber = Parent.prototype; }
When using, the method is as follows
extend(Cat,Animal); var cat1 = new Cat("Big hair","yellow"); alert(cat1.species); // animal
This extend function is how the YUI library implements inheritance.
Also, to illustrate, the last line of the function body
Child.uber = Parent.prototype;
It means to set a uber attribute for the child object, which directly points to the prototype attribute of the parent object. (uber is a German word, meaning "up" and "up.") this is equivalent to opening a channel on the child object to directly call the methods of the parent object. This line is placed here only to realize the completeness of inheritance. It is purely standby.
5, Copy inheritance
Introduction: the above uses prototype object to realize inheritance. We can also change our thinking and use the "copy" method to realize inheritance. In short, if all the properties and methods of the parent object are copied into the child object, can inheritance not also be realized? So we have a fifth way.
First, put all the invariant properties of Animal on its prototype object.
function Animal(){} Animal.prototype.species = "animal";
Then, write a function to copy the attributes.
function extend2(Child, Parent) { var p = Parent.prototype; var c = Child.prototype; for (var i in p) { c[i] = p[i]; } c.uber = p; }
This function copies the attributes in the prototype object of the parent object to the prototype object of the Child object one by one.
When using, write this:
extend2(Cat, Animal); var cat1 = new Cat("Big hair","yellow"); alert(cat1.species); // animal