Inheritance is one of the most talked about concepts in OO languages. Many OO languages support two types of inheritance: interface inheritance and implementation inheritance. Interface inheritance inherits only method signatures, whereas implementation inheritance inherits the actual methods.

— This abstract is selected from JavaScript Advanced Programming (3rd Edition)



Interface inheritance cannot be implemented in ECMAScript because functions have no signatures. ECMAScirpt only supports implementation inheritance, and its implementation inheritance mainly relies on the prototype chain.

Prototype chain

The prototype chain is described in ECMAScript as the primary method for implementing inheritance.

Basic idea: Use stereotypes to make one reference type inherit the properties and methods of another.

PS: Each constructor has a prototype object, which contains a pointer to the constructor, and each instance contains an internal pointer to the prototype object.

If the stereotype object is equal to an instance of another type, then the stereotype object will contain a pointer to another stereotype, which will also contain a pointer to another constructor. Another prototype is an instance of another type, and so on, forming a chain of instances and prototypes.

JS code:

function SuperType(){
    this.property = true;
};
SuperType.prototype.getSuperValue = function() {return this.property;
};

function SubType(){
    this.subproperty = false; } // SuperType subtype.prototype = new SuperType(); SubType.prototype.getSubValue =function() {return this.subproperty;
};

var instance = new SubType();
alert(instance.getSuperValue());    // true

Copy the code

The code above defines two types: SuperType and SubType. Each type has an attribute and a method. The main difference is that SubType inherits from SuperType, which is achieved by creating an instance of SuperType and assigning that instance to subType.prototype. The essence of the implementation is to rewrite the prototype object and replace it with an instance of a new type.

Constructor now points to SuperType because the constructor from SubType. Prototype was overwritten.

Downside: When inheritance is implemented through a stereotype, the stereotype actually becomes an instance of another type. Thus, the original instance property becomes the prototype property. The following code can illustrate the problem:

JS code:

function SuperType(){
    this.colors = ["red"."blue"."green"];
}

function SubType(){ } SubType.prototype = new SuperType(); Var instance1 = new SubType(); instance1.colors.push("black"); 
alert(instance1.colors); //"red,blue,green,black"

var instance2 = new SubType(); 
alert(instance2.colors); //"red,blue,green,black"

Copy the code

PS: When creating instances of subtypes, arguments cannot be passed to the supertype constructor; This is also the deficiency of prototype chain inheritance.



Borrow constructors [forge objects or classical inheritance]

Basic idea: Call the supertype constructor inside the subtype constructor. Functions are simply objects that execute code in a particular environment, so you can also execute constructors on (future) newly created objects by using the apply() and call() methods.

JS code:

function SuperType(){
    this.colors = ["red"."blue"."green"];    
}

function SubType(){// SuperType supertype.call (this); } var instance1 = new SubType(); instance1.colors.push("black");
alert(instance1.colors);    //"red,blue,green,black"

var instance2 = new SubType();
alert(instance2.colors);    //"red,blue,green"

Copy the code

By using the call() method [or apply() method] in the above code, we are actually calling the SuperType constructor in the context of the newly created SubType instance. This will execute all the object initialization code defined in the SuperType() function on the new SubType object. As a result, each instance of SubType has its own copy of the Colors attribute.

PS: One big advantage of borrowing constructors over stereotype chains is that arguments can be passed to supertype constructors in subtype constructors, which are not exemplalized here, just properties of the Call () method [or apply() method].

Disadvantages: Methods are defined in constructors, so function reuse is out of the question. Furthermore, methods defined in the stereotype of a supertype are also invisible to subtypes, resulting in only the constructor schema being used for all types.



Combinatorial inheritance [pseudo-classical inheritance]

Basic idea: an inheritance pattern that combines prototype chains and techniques borrowed from constructors to take advantage of the best of both. The idea behind this is to use stereotype chains to inherit stereotype attributes and methods, while borrowing constructors to inherit instance attributes.

JS code: 

function SuperType(name){
    this.name = name;
    this.colors = ["red"."blue"."green"];
}

SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){
    //继承属性 
    SuperType.call(this, name);
    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(); / / 27Copy the code

The SuperType constructor defines two attributes: name and colors. The SuperType prototype defines a method sayName(). The SubType constructor calls the SuperType constructor with the name argument and then defines its own property, age. We then assign an instance of SuperType to the prototype of SubType, and define the method sayAge() on that new prototype. This allows two different instances of SubType to have their own attributes, including the colors attribute, and use the same method.

Composite inheritance avoids the defects of stereotype chains and borrowed constructors, and combines their advantages to become the most common inheritance pattern in JavaScript. Also, instanceof and isPrototypeOf() can be used to identify objects created based on composite inheritance.


Primary inheritance

Basic idea: Stereotypes allow you to create new objects based on existing objects without having to create custom types. Refer to the following function:

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

Copy the code

Inside the object() function, a temporary constructor is created, the passed object is used as a prototype of the constructor, and a new instance of the temporary type is returned. In essence, object() makes a shallow copy of the object passed into it.

PS: This archetypal inheritance requires that there must be an object that can be used as a basis for another object. If such an object exists, you can pass it to the object() function and modify the resulting object as needed.

ECMAScript 5 normalizes primitive inheritance by adding the object.create () method.

This method takes two arguments

  1. Object and (optional) used as the prototype for the new object
  2. An object that defines additional properties for a new object.

Object.create() behaves the same as the Object () method when passed a parameter.


JS code:

var person = {
    name: "Nicholas",
    friends: ["Shelby"."Court"."Van"]}; var anotherPerson = Object.create(person); anotherPerson.name ="Greg";
anotherPerson.friends.push("Rob");

var yetAnotherPerson = Object.create(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends);    //"Shelby,Court,Van,Rob,Barbie"

Copy the code

The second argument to the PS: object.create () method has the same format as the second argument to the object.defineProperties () method

Again, no explanation here.

Application scenario: Old-style inheritance is perfectly fine if you just want one object to be similar to another, but attributes that contain reference type values will always share corresponding values, just as with the stereotype pattern.


Parasitic inheritance

The basic idea: Create a function that just encapsulates the inheritance process, internally enhances the object in some way, and finally returns the object as if it had really done all the work.

JS code:

function createAnother(original){ 
    var clone= object(original); // Create a new object clone. SayHi = by calling the functionfunction(){// Somehow enhance the object alert("hi");
};
    return clone; } var person = {name:"Nicholas",
    friends: ["Shelby"."Court"."Van"]}; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"

Copy the code

A new object [anotherPerson] is returned based on person; The new object not only has all the attributes and methods of Person, but also has its own sayHi() method.

Applicable scenarios:Parasitic inheritance is also a useful pattern in cases where objects are primarily considered rather than custom types and constructors.



Parasitic combinatorial inheritance

Here’s an example of combinatorial inheritance: In any case, the supertype constructor is called twice: once when the subtype stereotype is created and once inside the subtype constructor. Subtypes end up containing all of the instance properties of the supertype object, but we have to override these properties when we call the subtype constructor.

Here is combinatorial inheritance:

JS code:

function SuperType(name){
    this.name = name;
    this.colors = ["red"."blue"."green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};

functionSubType(name, age){ SuperType.call(this, name); // Call SuperType() this.age = age; } SubType.prototype = new SuperType(); / / the first call SuperType () SubType. The prototype. The constructor = SubType; SubType.prototype.sayAge =function(){
    alert(this.age);
};

Copy the code

The first time the SuperType constructor is called, subtype. prototype gets two attributes :name and colors; They are both instance properties of SuperType, but are now in the SubType stereotype;

When the SubType constructor is called, the SuperType constructor is called a second time, this time creating the instance attributes name and colors on the new object

Thus, these two properties mask the two properties of the same name in the stereotype.

The basic idea of parasitic combinatorial inheritance is to inherit properties by borrowing constructors and methods by using a hybrid form of prototype chains.

JS code:functioninheritPrototype(subType, superType){ var prototype = object(superType.prototype); Prototype. constructor = subType; // Add object subtype. prototype = prototype; // Specify the object}Copy the code

This function takes two arguments: a subtype constructor and a supertype constructor.

Inside the function, the first step is to create a copy of the supertype stereotype.

The second step is to add the Constructor attribute to the created copy to make up for the loss of the default constructor attribute by rewriting the stereotype.

Finally, the newly created object (that is, the copy) is assigned to the prototype of the subtype.

This way, we can replace the assignment of subtype stereotypes in the previous example with statements that call the inheritPrototype() function.

JS code:

function SuperType(name){
    this.name = name;
    this.colors = ["red"."blue"."green"];
}
SuperType.prototype.sayName = function(){
    alert(this.name);
};

function SubType(name, age){
    SuperType.call(this, name);
    this.age = age;
}

inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function(){
    alert(this.age);
};

Copy the code

PS: Parasitic combinatorial inheritance is efficient in that it calls the SuperType constructor only once and thus avoids creating unnecessary attributes on subtype. prototype, while keeping the prototype chain unchanged.

Parasitic combinatorial inheritance is generally considered by developers to be the ideal inheritance paradigm for reference types.



ESMA5 inheritance can be summarized as follows:


ECMA6 class inheritance, ECMA6 class inheritance.


Finally, HAVE a great weekend!