1. Inheritance mode 1: prototype chain

The prototype chain is the most primitive pattern for implementing inheritance through the Prototype property. For example:

// Parent constructorfunction dad(){
    this.name = 'pp'}; // Parent - Prototype attribute dad.prototype.sayMyname =function() {returnthis.name; }; // subclass - constructorfunction son(){
    this.sonName = 'ap'} // Sublevel - Prototype attribute son.prototype.saySonName =function() {returnthis.sonName; } // Inherit the parent's prototype attribute son.prototype = new dad(); // Redirect son's constructor to the son constructor. Otherwise it will lead to Dad. son.prototype.constructor = son var p = new son(); console.log(p.sayMyname()) // pp console.log(p.saySonName()) // ap son.prototype.__proto__ == dad.prototype //true
  son.prototype.__proto__.__proto__ == Object.prototype //true
Copy the code

Explain how the son instance found the parent stereotype attribute sayMyname?

  1. I will first look for the son object itself. If I can’t find it, I will look for the son prototype.
  2. If son prototype is not found, search on son.prototype.proto.
  3. And so on until you find the desired property or method, or you reach the top of the prototype chain object.prototype

Disadvantages of using stereotype inheritance

  1. Attributes of reference types in the stereotype chain are shared by all instances, that is, all instance objects use the same data and interact with each other. Such as:
function dad(){
    this.obj = {a:1,b:2}
}
function son(){ } son.prototype = new dad(); son.prototype.constructor = son; var son1 = new son(), son2 = new son(); Obj // {a:1,b:2} son2.obj // {a:1,b:2} son2.obj // {a:1,b:2} son2.obj // {a:1,b:2} son2.obj // {a:1,b:2} son2.obj //{a:2,b:2}Copy the code
  1. Cannot pass a parameter to the parent constructor

2. Inheritance method 2: Use call and apply to implement inheritance by borrowing constructors

The parent constructor is called directly from the child constructor

 function dad(name,obj={a:1}){
 	this.name =name;
 	this.obj =obj;
 }
 dad.prototype.method_name = function(){
 };
 functionSon (name){dad.call(this,name) // implement inheritance //or //dad.apply(this, arguments)} // Solve the problem that stereotype inheritance cannot pass arguments to parent constructors. var son1 = new son('pp'),
     son2 =new son('ap'); Console. log(son1.name)//pp console.log(son2.name)//ap // Solve the problem that the prototype inherits reference type data so that the instance shares a copy of the data son1.obj. console.log(son1.obj)//{a: 2} console.log(son2.obj)//{a: 1} son1.method_name() //son1.method_name is not afunction
Copy the code

From the above example, you can see the advantages of constructor inheritance

  1. All instances do not share reference attributes, which means that each instance has an independent copy of the attributes inherited from its parent class. Any modification of the data content of a reference attribute by one instance does not affect the other instances
  2. You can pass parameters to a parent function

Disadvantages:

  1. Since all properties and methods are no longer shared by all instances, those public properties and methods are created repeatedly, causing additional memory overhead.
  2. Unable to inherit stereotype properties from parent class

3. Inheritance mode 3: Combination inheritance

Combinatorial inheritance = stereotype chain inheritance + constructor inheritance

functiondad(name){ this.name = name; This. Arr = [1, 2]; } dad.prototype.getName =function(){
	console.log(this.name);
};
functionson(name,sex){ dad.call(this,name); // Implement the constructor from this.sex = sex; } son.prototype=new dad(); / / implementation prototype chain inherit son. Prototype. Constructor = son; son.prototype.getSex =function(){
	console.log(this.sex);	
};
var son1 = new son('pp'.'boy'),
    son2 = new son('ap'.'girl'); son1.getSex(); //boy son1.getName(); //pp son2.getSex(); //girl son2.getName(); / / ap console. The log (son1. Arr) / / [1, 2] the console log (son2. Arr) / / [1, 2] son1. Arr. Push (3); The console. The log (son1. Arr) / / [1, 2, 3]. The console log (son2. Arr) / / [1, 2]Copy the code

Downside: The parent’s constructor was called twice, first when the child prototype object was created and again when call or apply was used inside the child constructor

4. Inheritance mode four: Original type inheritance

Primitive inheritance is implemented by passing an object as a prototype to create an object into a function that builds a new object. You can define and encapsulate a method, or you can use Object.create().

 var obj={
	name:'pp', arr: [1, 2],}function creatObj(o){
	function f() {}; f.prototype = o;returnnew f(); } var a = creatObj(obj), b = creatObj(obj); a.arr.push(3); console.log(a.arr); / / [1, 2, 3]. The console log (b.a rr); / / [1, 2, 3] a.n ame ='a';
	b.name = 'b'; console.log(a.name); //a console.log(b.name); //b console.log(a.__proto__ === obj) //true
	console.log(b.__proto__ === obj) 	 //trueConsole. log(a.__proto__.name) //pp console.log(b.__proto__.name) //pp // use object.create () var c = object.create (obj, { name : { value :'c'
 	}
 })
 console.log(c.name) // c
 console.log(c.__proto__ === obj) 	 // true
 console.log(c.__proto__.name)   //pp
	
Copy the code

Disadvantage: You can see that the child objects still share data of the same reference type

Parasitic inheritance

In the function that creates the subinstance, an instance is created using the inherited method, attributes and methods are added to the instance, and the instance is returned.

var obj={
	name : 'pp', arr: [1, 2]}function creatObj(obj,props){
	var object = Object.create(obj, props);
	object.getName = function() {return this.name;
	}
	return object;
}
var a = creatObj(obj,{
	name : {
		value : 'a'} }), b =creatObj(obj); console.log(a.getName()) // a console.log(b.getName()) //pp a.arr.push(3); The console. The log (a.a rr) / / [1, 2, 3]. The console log (b.a rr) / / [1, 2, 3]. The console log (a.n ame = = = a. __proto__. Name) / /false
console.log(b.name === b.__proto__.name)  //true
Copy the code

Resolution:

  1. You can add attributes and methods to the returned instance using custom functions, or you can pass attributes and methods through PRPS, the second argument to object.create (). None of these attributes and methods appear on __proto__.
  2. Weakness: There is no way to solve the problem of referencing type data.

Parasitic combinatorial inheritance

Description: Parasitic combinations are inherited to solve the problem of combinatorial inheritance calling the parent constructor twice.

  1. Composite inheritance: a child’s Prototype inherits its parent’s prototype through the new parent class.
  2. Parasitic combination: child’s Prototype inherits parent’s prototype through direct assignment
 function inheritFun(dad,son){
	son.prototype = Object.create(dad.prototype);
	son.prototype.constructor = son;
}
functiondad(name){ this.name=name; This. Arr = [1, 2]; } dad.prototype.getArr =function() {return this.arr;
}
function son(name,age){
	dad.call(this,name);
	this.age = age;
}
inheritFun(dad,son); 
son.prototype.getAge = function() {return `${this.name}already${this.age}At the age of `; } var son1 = new son('pp',18),
	son2 = new son('ap'19); console.log(son1.getAge())//'PP is 18 years old'Console. log(son2.getage ()) // AP is 19 years old son1.arr.push(3); The console. The log (son1. GetArr ()) / / [1, 2, 3]. The console log (son2. GetArr ()) / / [1, 2]Copy the code