JavaScript inheritance foundation explains of prototype chain borrowing constructor mixed mode original type inheritance parasitic inheritance parasitic combinatorial inheritance

  • 2020-03-30 03:42:36
  • OfStack

I said I was going to talk about JavaScript inheritance, but it's been a long time coming. Without further ado, get straight to the point.

Now that you want to learn about inheritance, prove that you already have some understanding of JavaScript object orientation. If there is anything you don't understand, please refer to "(link: #)".

Prototype chain

The easiest way to implement inheritance in JavaScript is to use a prototype chain and point the prototype of a subtype to an instance of the parent type, i.e., "subtype.prototype = new parent type ();" , the implementation method is as follows:


//Create a constructor for the parent type
function SuperType() {
  this.name = ['wuyuchang', 'Jack', 'Tim'];
  this.property = true;
}

//Add a method to the parent type
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

//Create a constructor for the subtype
function SubType() {
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

//To implement the key step of inheritance, the prototype of the child type points to an instance of the parent type
SubType.prototype = new SuperType();

//Add a method to the subtype here only after implementing inheritance, otherwise you will be pointing to an instance of the parent type and the method will be null
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}



var instance1 = new SubType();
instance1.name.push('wyc');
instance1.test.push('h5');
alert(instance1.getSuerperValue());    // true
alert(instance1.getSubValue());      // false
alert(instance1.name);          // wuyuchang,Jack,Tim,wyc
alert(instance1.test);          // h1,h2,h3,h4,h5


var instance2 = new SubType();
alert(instance2.name);          // wuyuchang,Jack,Tim,wyc
alert(instance2.test);          // h1,h2,h3,h4

You can see that the code above is a simple inheritance through the prototype chain, but you can see that there are some problems in the test code example. I believe that children who have read my blog post "(link: #)" must know the existence of the prototype chain code The first problem is that because the stereotype of the subtype is an instance of the parent type, the attribute of the parent type contained in the stereotype of the subtype, the stereotype attribute that references the value of the type is Shared by all instances . The instance1.name.push('wyc') of the above code; Can prove the existence of this problem. The second problem with the prototype chain is: When creating an instance of a subtype, you cannot pass arguments to the constructor of a supertype . Therefore, we rarely use the prototype chain alone in actual development.  

  Borrow constructor

To solve the two problems in the prototype chain, developers began using a technique called borrowing constructors to solve the problems in the prototype chain. This technique is also fairly simple to implement by simply calling the constructor of the parent type within the constructor of the child type. Remember, functions are simply objects that execute code in a particular environment, so they can The constructor is executed through the apply() or call() methods . The code is as follows:


//Create a constructor for the parent type
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

//Add a method to the parent type
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

//Create a constructor for the subtype
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

//Add a method to the subtype here only after implementing inheritance, otherwise you will be pointing to an instance of the parent type and the method will be null
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}



var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
// alert(instance1.getSuerperValue());    // error  An error 
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
// alert(instance2.getSuerperValue());    // error  An error 
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

You can see the above code within the constructor of the SubType SubType by calling the parent type "supertype.call (this, name);" , which enables inheritance of properties, and the ability to pass arguments to parent types when instances of subtypes are created, but a new problem arises. You can see that I defined a method, testFun, in the constructor of the parent type, and a method, getSuperValue, in the prototype of the parent type. But in the Instantiated subtypes are still unable to call methods defined in the stereotype of the parent type GetSuperValue can only call the constructor method in the parent type: testFun. This is the same as creating an object using only the constructor pattern, making the function non-reusable. Given these problems, techniques that borrow constructors are also rarely used alone.

Combinatorial inheritance (prototype chain + borrowing constructor)

As the name implies, composite inheritance is a pattern that combines the use of a prototype chain with the advantages of a constructor. The implementation is also very simple, since it is a combination, it certainly combines the advantages of both sides, namely The prototype chain inherits methods, while the constructor inherits properties . The specific code is as follows:


//Create a constructor for the parent type
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

//Add a method to the parent type
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

//Create a constructor for the subtype
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

SubType.prototype = new SuperType();

//Add a method to the subtype here only after implementing inheritance, otherwise you will be pointing to an instance of the parent type and the method will be null
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}



var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
alert(instance1.getSuerperValue());      // true
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
alert(instance2.getSuerperValue());      // true
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

The above code passes supertype.call (this, name); Inherits properties of the parent type by subtype.prototype = new SuperType(); A method that inherits a parent type. The above code conveniently solves the problems encountered by the prototype chain and borrowing constructor, and has become the most common method of instance inheritance in JavaScript. But is not without its drawbacks as well as mixed mode, you can see in the above code at the time of inheritance method actually has inherited the parent type attributes, only for reference types belong to share at this time, so in a subtype of constructor calls within the parent types constructor which inherits the parent type attributes and to override the inherited attributes in the prototype, so call two constructors obviously is not necessary, but is there any way to solve? To solve this problem, look at the following two patterns.

Original pattern inheritance

Unlike normal inheritance, primitive inheritance does not use strict constructors. Instead, prototypes allow you to create new objects based on existing objects without creating custom types. The specific code is as follows:


function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

Code example:



function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Tim']
}

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Bob');

var anotherPerson2 = object(person);
anotherPerson2.name = 'Jack';
anotherPerson2.friends.push('Rose');

alert(person.friends);  // wyc,Nicholas,Tim,Bob,Rose

Parasitic inheritance



function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

Examples of use:



function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
   

function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Rose']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

Parasitic combinatorial inheritance

We have mentioned the disadvantage of the composite pattern in javascript to realize inheritance, now we will solve it, the idea is, for constructor inheritance properties, and the prototype chain of mixed form inheritance method, that is, do not need to instantiate the constructor of the parent type in the inheritance method. The code is as follows:


function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}


function inheritPrototype(subType, superType) {
  var prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

All you need to do is "subtype.prototype = new SuperType(); Replace this line with inheritPrototype(subType, superType); Can. Parasitic composite inheritance is efficient in that it calls the parent constructor only once, avoiding the creation of unnecessary or redundant properties. At the same time, the prototype chain remains the same, so instanceof and isPrototypeof() can still be used normally. This is by far the most ideal way of inheritance, and is currently being transformed into this model. (YUI also USES this model.)

This blog post is a reference to "(link: #)". The code has been rewritten to be more specific and annotated to make it easier to understand. If there is a unique view of JS inheritance of children's shoes not stingy, reply to your views for your reference!


Related articles: