Prototype chain
Prototype chain has always been a confusing knowledge point in JS, but it is often asked in the interview, here I will make a summary, first introduce a relationship diagram:
To understand the prototype chain, we can start with the diagram above, which has three concepts:
1. Constructors: All functions in JS can be constructors, provided they are operated by the new operator;
function Parent(){ this.name = 'parent'; } parent1 = new Parent();} parent1 = new Parent();Copy the code
Parent1 receives new Parent(), and parent1 can be called the instance;
3. Prototype object: The constructor has a prototype property that initializes a prototype object;
Ii. Having made clear these three concepts, let’s talk about the relationship between these three concepts (refer to the figure above) :
1. An instance is obtained by applying the new operator to the JS function;
2. The constructor initializes a prototype, which initializes a prototype object. How does the prototype know which function initializes it? The original stereotype object has a constructor property that points to the constructor;
3. How does the instance object relate to the prototype object? The original instance object will have a __proto__ attribute that points to the prototype object corresponding to the constructor of the instance object;
If the name attribute is not found in the current Object, then the __proto__ attribute will be searched until the name attribute is not found in the Object. Otherwise, as long as the name attribute is found, then the attribute is present. From here we can see that the relationship between JS objects and their superiors is like a chain, which is called the prototype chain;
5. If you don’t understand the prototype chain, you can start with inheritance, because inheritance is based on the prototype chain;
How does the new operator work
Function (func){var t = {} t.prototype var o = t var k =func.call(o); if(typeof k === 'object'){ return k; }else{ return o; }} var parent1 = newObj(Parent) equivalent to new operation 1. A new object is created that inherits from func.prototype. 2. The constructor func is executed, and when it is executed, the corresponding argument is passed and the context (this) is specified as the new instance. 3. If the constructor returns a new object, that object replaces the entire new result. If the constructor does not return an object, the new result is the object created in Step 1.Copy the code
inheritance
Constructor implementation inheritance (constructor inheritance)
Function Parent(){this.name = 'parent1' this.play = [1,2,3]} function Child{paren.call (this); //apply this.type = 'parent2'; } Parent.prototype.id = '1' var child1 = new Child() console.log(child1.name)//parent1 console.log(child1.id)//undefined Var child2 = new Child(); var child2 = new Child(); child1.play[0] = 2; Console. log(child2.play)//[1,2,3]; console.log(child2.play)//[1,2,3]; console.log(child2.play)//[1,2,3];Copy the code
Two. Prototype chain implementation inheritance
Function Parent(){this.name = 'Parent' this.play = [1,2,3]} function Child(){this.type = 'Child '; } Child.prototype = new Parent(); Parent.prototype.id = '1'; var child1 = new Child(); Console. log(child1.name)//parent1 console.log(child1.id)//1 Var child2 = new Child(); child1.play[0] = 2; Console. log(child2.play)//[2,2,3] here I only change the instance object child1 to play array, but the instance prints the instance object child2 to paly array, which also changes, so we can draw the conclusion that the prototype chain inherits the reference type to the property. In all the above instance objects change this property, all the instance objects properties will change, there are certainly problems, now we back to the way inheritance inheritance (structure), 1 will find tectonic inheritance will not have this problem, so Actually tectonic inheritance and prototype chain inheritance can complement each other, thus we introduce a third way of inheritance; Prototype = new Parent(); parent.prototype = new Parent(); This operation assigns an instance of the parent class to the prototype of the child class, and then reproduces the prototype chain diagram above:Copy the code
Child.prototype = new Parent(); This operation gives the instance of the parent class to the Child’s prototype, so we can find the name of the parent through this, and this is the prototype chain, layer by layer, like a chain;
3. Combinatorial inheritance
Function Parent(){this.name = 'parent1' this.play = [1,2,3]} function Child{paren.call (this); //apply this.type = 'parent2'; } Child.prototype = new Parent(); Parent.prototype.id = '1' var child1 = new Child() console.log(child1.name)//parent1 console.log(child1.id)//1 var child2 = new Child(); child1.play[0] = 2; Console. log(child2.play)//[1,2,3] [1,2,3] [console.log(child2.play)//[1,2,3] So combinatorial inheritance is perfect? If we call the Parent function twice, once new Parent() and once parent.call (this), can we optimize it? We introduce a fourth method of inheritance;Copy the code
4. Combinatorial Inheritance (Optimization 1)
Function Parent(){this.name = 'parent1' this.play = [1,2,3]} function Child{paren.call (this); //apply this.type = 'parent2'; } Child.prototype = Parent.prototype; Id = '1' var child1 = new Child() console.log(child1.name)//parent1 console.log(child1.id)//1 var child2 = new Child(); child1.play[0] = 2; Console. log(child2.play)//[1,2,3] we changed to child.prototype = Parent. Prototype, so that Parent is called only once. Is there no problem in this way? We do the following operations: The console. The log (Child) prototype) constructor) / / Parent here we print found the constructor of the prototype of the Child becomes a Parent, Child, according to our understanding should be this creates the constructor is disorder, so we introduce the 5 kinds of inheritance optimizationCopy the code
V. Combinatorial Inheritance (Optimization 2)
Function Parent(){this.name = 'parent1' this.play = [1,2,3]} function Child{paren.call (this); //apply this.type = 'parent2'; } Child.prototype = Parent.prototype; Child. The prototype. The constructor Child / / change the Parent here. = prototype. Id = '1' var child1 = new Child () console.log(child1.name)//parent1 console.log(child1.id)//1 var child2 = new Child(); child1.play[0] = 2; Console. The log (child2. Play) / / [1, 2, 3]. Now we print the console log (Child) prototype) constructor) / / Child here to solve the problem, But we continue to print the console. The log (Parent. The prototype. The constructor) / / Child found the superclass constructor also appeared disorder, all of us through a median to solve this problem, the final version is: Function Parent(){this.name = 'parent1' this.play = [1,2,3]} function Child{paren.call (this); //apply this.type = 'parent2'; } var obj = {}; obj.prototype = Parent.prototype; Child.prototype = obj; Prototype = object.create (Parent. Prototype); Child.prototype.constructor = Child console.log(Child.prototype.constructor)//Child The console. The log (Parent. The prototype. The constructor) / / Parent with an intermediate obj, perfect solved the problemCopy the code