Yes, we have to understand the inheritance model first to understand the prototype chain of this thing.
One: Prototype chain
The basic idea is to have a reference type inherit the properties and methods of another reference type. To understand the prototype chain, we can first review the relationship between the constructor, the prototype, and the instance: each constructor has a prototype object that contains a pointer to the constructor, and the instance contains an internal pointer to the prototype object.
If we make the prototype object equal to an instance of another type, the prototype object at this time will contain a pointer to another prototype, and the corresponding other prototype also contains a pointer to another constructor. If another prototype is another type of instance, then the relationship is still valid. This is almost the so-called prototype chain concept.
Let's look at the relationship between the three by code:
1: The relationship between function and prototype
A. Each constructor has a prototype object
function Fun () {
}
Console.log (Fun.prototype); fun{} indicates that prototype is a prototype object
B. A prototype object (that is, the prototype property) automatically obtains a constructor property that contains a pointer to the function (fun) of the prototype property that identifies the type of the instantiated object
If a property method of the same name in the stereotype is defined in the constructor, the instance invokes the redefined property and method
function fun (name) {
Console.log (fun.prototype.name = = this.name) ;//true (YJH)
THIS.name = "Yjh1″;
Console.log (this.name);//YJH1
Console.log (fun.prototype.name = this.name);//false (YJH,YJH1)
}
Fun.prototype = {
Constructor:fun,
Name: ' Yjh '
}
var fun1 = new Fun ();
Console.log (fun.prototype.cons Tructor = = fun); True
Console.log (fun1.constructor = = fun);//true
2: Instantiating the relationship between the object and the prototype
A. When a function instantiates an object using the new operator, the object contains an intrinsic __proto__ attribute that only exists between the instance object and the prototype object
Such as:
function Fun (name,age) {
THIS.name = name;
This.age = age;
This.sayname = function () {
alert (this.name);
}
}
Fun.prototype = {
Constructor:fun,
Age:22,
Sayname:function () {
alert (this.age);
}
}
var fun1 = new Fun ("Yjh", "23″");
Console.log (fun1.__proto__)//fun {age= "22″, Sayage=function ()}
Console.log (fun1.__proto__ = = Fun.prototype); True
3: Relationship between instance object and function (constructor)
A. When a function instantiates an object using the new operator, the this object in the constructor is an instance object, and the instance object gets the properties and methods bound to this
Such as:
function Fun (name,age) {
THIS.name = name;
This.age = age;
This.sayname = function () {
alert (this.name);
}
}
var fun1 = new Fun ("Yjh", "23″");
Fun1.sayname (); Yjh
4: Relationship between function (constructor) and instance object, prototype
When you invoke a materialized object property, you first search for the properties and methods defined by the instance object itself, and if not, continue searching for the prototype
function Fun (name,age) {
THIS.name = name;
This.age = age;
This.sayname = function () {
alert (this.name);
}
}
Fun.prototype.age = "22″;
Fun.prototype.sayAge = function () {
alert (this.age);
}
var fun1 = new Fun ("Yjh", "23″");
Fun1.age = 24;
Fun1.sayage (); 24, invokes the method in the prototype;
The prototype chain is powerful and can be used to implement inheritance, but when you implement inheritance with a prototype chain, you cannot use object literals to create a prototype method, because it overrides the prototype chain. Such as:
function Supertype () {
This.property = true;
}
SuperType.prototype.getSuperValue = function () {
return this.property;
};
Function subtype () {
This.subprotype = false;
}
Subtype.protopyte = new Supertype ();
Subtype.protopyte = {
Getsubvalue:function () {
return this.subproperty;
},
Someothermethod:function () {
return false;
}
};
var instance = new Subtype ();
Alert (Instance.getsupervalue ()); Error
The main problem with prototype chain implementation inheritance comes from prototypes that contain reference type values. Because when inheriting through a prototype, the prototype actually becomes an instance of another type, so the instance attribute of the prototype becomes the current prototype property. Another problem is that when you create an instance of a subtype, you cannot pass parameters to the superclass constructor.
Second: Borrow the constructor function
The use of constructor techniques is sometimes called a forgery object or classical inheritance. The basic idea is to call the superclass constructor inside the subtype constructor. We know that a function is just an object that executes code in a particular environment, so you can also perform constructors on newly created objects by using the Apply () and call () methods. As follows:
function Supertype () {
This.color = ["Red", "Blue", "green"];
}
Function subtype () {
Supertype.call (this);
}
var Instance1 = new subtype ();
Instancel.colors.push ("Black");
alert (instancel.colors); "Red,blue,green,balck"
var instance2 = new subtype ();
alert (instance2.colors); "Red,blue,green"
Above is the call () method that invokes the Supertype constructor in the newly created subtype instance environment, which executes all the object initialization code defined in the Supertype () function on the new subtype object.
Pass parameters:
As I said earlier, the prototype chain cannot pass parameters, and the constructor just has this advantage.
As an example:
function Supertype (nmae) {
THIS.name = name;
}
Function subtype () {
Supertype.call (This, "Nicholas");
this.age = 29;
}
var instance = new Subtype ();
alert (instance.name); "Nicholas";
alert (instance.age); 29
If you only use the borrowed constructor to inherit, then there is also a bit of a disadvantage, that is, the method is defined in the constructor, the function does not have the effect of reuse.
Three: Combinatorial inheritance
Combinatorial inheritance is also called perjury classical inheritance, mainly refers to the prototype chain and the use of the constructor to combine the technology to play the two long one of the inheritance model. The basic idea is to inherit the prototype property and method by using the prototype chain, and to inherit the instance property by borrowing the constructor.
As follows:
function Supertype () {
THIS.name = name;
This.colors = ["Red", "Blue", "green"];
}
SuperType.prototype.sayName = function () {
alert (this.name);
}
Function subtype (name,age) {
Supertype.call (This,name); Inheritance Properties
This.age = age;
}
Subtype.prototype = new Supertype ();
SubType.prototype.constructor = subtype;
SubType.prototype.sayAge =function () {
alert (this.age);
}
var Instance1 = new Subtype ("Nicholas", 29);
Instance1.colors.push ("Black");
alert (instance1.colors); "Red,blue,green,black"
Instance1.sayname (); "Nicholas"
Instance1.sayage (); 29
var instance2 = new Subtype ("Greg", 27);
alert (instance2.colors); "Red,blue,green"
Instance2.sayname (); "Greg."
Instance2.sayage (); 27
Composite inheritance is one of the most commonly used inheritance patterns in JavaScript, and instanceof and isprototypeof () can also recognize objects created based on composite inheritance.
Four: Archetypal inheritance
This method does not use a strict constructor, the basic idea is that the prototype can be based on existing objects to create new objects, and do not have to create a custom type. In fact, this is essentially a shallow copy (shallow copy). As follows:
var person = {
Name: "Nicholas";
friends:["Shelby", "Court", "Van"
};
var Anotherperson = object (person);
Anotherperson.name = "Greg";
AnotherPerson.friends.push ("Rob");
var yetanotherperson =object (person);
Yetanotherperson.name = "Linda";
YetAnotherPerson.friends.push ("Barbie");
alert (person.friends); "Shelby,court,van,rob,barbie"
This inheritance pattern requires that you have an object that can be used as the basis for another object, and that if you have one, you can pass it to the object () function, and then modify the object you want based on the specific requirements.
In ECMAScript5, prototype inheritance is regulated by the addition of the Object.creat () method. This method takes two parameters: an object that is used as a prototype of the new object and an object that defines additional attributes for the new object (optional). However, this method is only supported by all browsers, for example, IE9 the following love is not supported.
V: Parasitic inheritance
This way of inheritance is closely related to the archetypal inheritance of a thinking. The basic idea is to create a function that encapsulates only the inheritance process, which in some way enhances the object, and finally, as it does all the work, returns the object. As follows:
function Creatanother (original) {
var Clone = Object (original); To create a new object by calling a function
Clone.sayhi = function () {///To enhance this object in some way
Alert ("HI");
};
return clone; returns this object
}
In this example, the Creatanother () function receives a parameter, which is the object that will be the base of the new object. This object (original) is then passed to the object () function to assign the returned result to clone. Add a new method to the Clone object Sayhi (), and finally return to clone.
PS: Using parasitic inheritance to add a function to an object can degrade efficiency by not being able to reuse the function.
VI: Parasitic modular inheritance
Composite inheritance is one of the most common inheritance patterns, but it is also deficient. The problem is that, in any case, the two-time superclass constructor is invoked: one at a time when a subtype prototype is created, and another within a subtype constructor.
Look at a combination of examples of inheritance:
function Supertype (name) {
THIS.name = name;
This.clone = ["Red", "Blue", "green"];
}
SuperType.prototype.sayName = function () {
alert (this.name);
}
Function subtype (name,age) {
Supertype.call (This,name);
This.age = age;
}
Sybtype.prototype = new Supertype ();
SubType.prototype.constructor = subtype;
SubType.prototype.sayAge = function () {
alert (this.age);
}
The so-called parasitic combinatorial inheritance is to inherit the attribute by borrowing the constructor, and inheriting the method through the hybrid form of the prototype chain. The basic mode is as follows:
function Inheritprototype (subtype,supertype) {
var prototype = object (Supertype.prototype); Creating objects
Prototype.constructor = subtype; Enhanced objects
Subtype.prototype = prototype; Specify the Object
}
This example Inheritprototype () function implements the simplest form of a parasitic combination that receives two parameters: the subtype constructor and the superclass constructor.
Inheritance of constructors
Five methods of "inheritance" between objects.
For example, there is now a constructor for an "animal" object.
function Animal () {
This.species = "Animal";
}
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"?
First, constructor binding
The first method is also the easiest way to bind the parent object's constructor to a child object by using the call or Apply method, which is to add a row to the child object constructor:
function Cat (name,color) {
Animal.apply (this, arguments);
THIS.name = name;
This.color = color;
}
var cat1 = new Cat ("hairy", "yellow");
alert (cat1.species); Animals
Second, prototype mode
The second method is more common and uses the prototype property.
If the prototype object of "cat" points to a animal instance, then all instances of "cat" can inherit the animal.
Cat.prototype = new Animal ();
Cat.prototype.constructor = Cat;
var cat1 = new Cat ("hairy", "yellow");
alert (cat1.species); Animals
The first line of code, we point the cat's prototype object to a animal instance.
Cat.prototype = new Animal ();
It is equivalent to completely removing the original value of the prototype object and then assigning a new value. But what does the second line mean?
Cat.prototype.constructor = Cat;
It turns out that any prototype object has a constructor property that points to its constructor. If there is no "Cat.prototype = new Animal ();" In this line, Cat.prototype.constructor is pointing 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 property that invokes the constructor property of the prototype object by default.
Alert (Cat1.constructor = = Cat.prototype.constructor); True
Therefore, in the run "Cat.prototype = new Animal ();" After this line, Cat1.constructor also points to animal!
Alert (Cat1.constructor = = Animal); True
This obviously leads to the disorder of the inheritance chain (CAT1 is obviously generated with the constructor cat), so we have to correct it manually and change the constructor value of the Cat.prototype object to Cat. That's what the second line means.
This is a very important point to be sure to follow when programming. This is followed, that is, if the prototype object is replaced,
O.prototype = {};
The next step, then, is necessarily to add the constructor attribute to the new prototype object and refer back to the original constructor.
O.prototype.constructor = O;
Third, direct inheritance prototype
The third approach is to improve the second approach. Because of the animal object, immutable properties can be written directly to Animal.prototype. So, we can also let cat () skip Animal () and inherit Animal.prototype directly.
Now, let's rewrite the animal object first:
function Animal () {}
Animal.prototype.species = "Animal";
Then, the cat's prototype object is then pointed to the animal prototype object, which completes the inheritance.
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat ("hairy", "yellow");
alert (cat1.species); Animals
Compared to the previous method, the advantage of this is that it is more efficient (without executing and establishing animal instances), and compares memory. The disadvantage is that Cat.prototype and Animal.prototype now point to the same object, and any changes to Cat.prototype will be reflected in Animal.prototype.
So, the above section of code is actually problematic. Please look at the second line
Cat.prototype.constructor = Cat;
This sentence actually put the Animal.prototype object's constructor attribute also to get rid of!
alert (Animal.prototype.constructor); Cat
The use of empty objects as an intermediary
Because of the disadvantages of "direct inheritance prototype", there is a fourth way to use 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 point, modifying the prototype object of CAT will not affect the animal prototype object.
alert (Animal.prototype.constructor); Animal
We encapsulate the above method into a function that is easy to use.
function extend (child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F ();
Child.prototype.constructor = child;
Child.uber = Parent.prototype;
}
When used, the method is as follows
Extend (Cat,animal);
var cat1 = new Cat ("hairy", "yellow");
alert (cat1.species); Animals
This extend function, is Yui library How to implement the method of inheritance.
In addition, note that the last line of the function body
Child.uber = Parent.prototype;
It means to set a Uber property for the child object, which points directly to the parent object's prototype property. (Uber is a German word, meaning "up", "upper layer".) This is equal to opening a channel on a child object that can directly invoke the method of the parent object. This line is placed here only to achieve the completeness of inheritance, and is purely a standby nature.
V. Copy inheritance
Above is the adoption of the prototype object, the implementation of inheritance. We can also change a way of thinking, purely using the "copy" method to achieve inheritance. Simply put, if you copy all the properties and methods of a parent object into a child object, can you not inherit it? So we have a fifth method.
First, all the invariant attributes of animal are placed on its prototype object.
function Animal () {}
Animal.prototype.species = "Animal";
Then, write a function that implements the purpose of the property copy.
function Extend2 (Child, Parent) {
var p = parent.prototype;
var c = Child.prototype;
for (var i in P) {
C[i] = P[i];
}
C.uber = p;
}
The function is to copy the properties of the parent object's prototype object, one by one to the prototype object of the child object.
When used, write like this:
Extend2 (Cat, Animal);
var cat1 = new Cat ("hairy", "yellow");
alert (cat1.species); Animals
Inheritance of non-constructors
One, what is the "non-constructor" inheritance?
For example, now there is an object called "Chinese".
var Chinese = {
Nation: ' China '
};
There is also an object called "Doctor".
var doctor ={
Career: ' Doctor '
}
How can I let "Doctor" to Inherit "Chinese", that is to say, how can I produce a "Chinese Doctor" object?
Notice here that both objects are normal objects, not constructors, and cannot be implemented with the constructor method.
Two, Object () method
The JSON-formatted inventor Douglas Crockford, presents an object () function that can do this.
function Object (o) {
function F () {}
F.prototype = O;
return new F ();
}
This object () function, in fact, only do one thing, that is, the object of the prototype attribute, point to the parent object, so that child objects and the parent object together.
When used, the first step is to generate child objects on the basis of the parent object:
var Doctor = object (Chinese);
Then, plus the properties of the child object itself:
Doctor.career = ' Doctor ';
At this point, the child object has inherited the properties of the parent object.
alert (doctor.nation); China
Third, shallow copy
In addition to using the "prototype chain", there is another idea: the parent object's attributes, all copied to the child object, can also implement inheritance.
The following function is making a copy:
function Extendcopy (p) {
var c = {};
for (var i in P) {
C[i] = P[i];
}
C.uber = p;
return C;
}
When used, write like this:
var doctor = extendcopy (Chinese);
Doctor.career = ' Doctor ';
alert (doctor.nation); China
However, there is a problem with such a copy. That is, if the parent object's properties are equal to an array or another object, the child object actually gets only a memory address, not a real copy, so there is a possibility that the parent object has been tampered with.
See, now add a "birthplace" attribute to Chinese, whose value is an array.
chinese.birthplaces = [' Beijing ', ' Shanghai ', ' Hong Kong '];
Through the Extendcopy () function, doctor inherits the Chinese.
var doctor = extendcopy (Chinese);
Then, we add a city for doctor's "birthplace":
Doctor.birthPlaces.push (' Xiamen ');
What happened? Chinese's "birthplace" has also been changed!
alert (doctor.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
alert (chinese.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
So, extendcopy () just copies the basic type of data, and we call this copy "shallow copy." This is how early jquery implements inheritance.
Four, deep copy
The so-called "deep copy" is the ability to achieve the true meaning of the array and the copy of the object. Its implementation is not difficult, as long as the recursive call "shallow copy" on the line.
function Deepcopy (p, c) {
var c = C | | {};
for (var i in P) {
if (typeof p[i] = = = ' object ') {
C[i] = (P[i].constructor = = Array)? [] : {};
Deepcopy (P[i], c[i]);
} else {
C[i] = P[i];
}
}
return C;
}
When used, write this:
var doctor = deepcopy (Chinese);
Now, add a property to the parent object, and the value is an array. Then, modify the property on the child object:
chinese.birthplaces = [' Beijing ', ' Shanghai ', ' Hong Kong '];
Doctor.birthPlaces.push (' Xiamen ');
At this point, the parent object will not be affected.
alert (doctor.birthplaces); BEIJING, Shanghai, Hong Kong, Xiamen
alert (chinese.birthplaces); BEIJING, Shanghai, Hong Kong
Currently, the jquery library is using this inheritance method.