Borrow constructor inheritance

Prototype chain inheritance (using prototype chain to achieve inheritance)

Combinatorial inheritance

  • Combinatorial inheritance optimization 1

  • Combinatorial inheritance optimization ii

ES6 inherit

JS object-oriented knowledge, inheritance is difficult to compare the abstract of a piece of content, there are many kinds of methods and implementation inheritance, each method and each have advantages and disadvantages, more let a person collapse, the need for object-oriented knowledge of objects, the prototype, the prototype chain, constructor, such as basic knowledge to master thoroughly, otherwise the JS elevation in the sixth chapter inheritance is also look not to understand, There are many articles on the Internet, read so many inheritance is still not very clear, the so-called know a lot of truth but still bad this life.

Below I combine my own understanding, and refer to “JS elevation” and online articles, summarize several methods to achieve inheritance and advantages and disadvantages, this article is suitable for going out before the interview shorthand.

Borrow constructor inheritance

function Parent0(){

    this.name = “parent0”;

    this.colors = [“red”,”blue”,”yellow”];

}

function Child0(){

Parent0.call( this ); / / or apply

    this.type = “child0”;

}

In line 6, the Parent0 constructor is invoked in the child class (Child0). By calling this, the parent constructor refers to the reference to the instantiation object of the child class, resulting in the properties of the parent class being mounted to the instance of the child class when the parent class is executed.

new Child0().name; // Parent0

new Child0().colors; // (3) [“red”, “blue”, “yellow”]

But in this way, you can’t inherit from the parent prototype

Parent0. Prototype. Sex = “male “;

Parent0.prototype.say = function() {

    console.log(” Oh,My God! “);

}

new Child0().sex; // undefined

// Uncaught TypeError: (intermediate value).say is not a function

new Child0().say();

Disadvantages: Child1 does not inherit from Parent1’s prototype object, and does not really implement inheritance (partial inheritance)

Prototype chain inheritance (using prototype chain to achieve inheritance)

function Parent1(){

    this.name = “parent1”;

    this.colors = [“red”,”blue”,”yellow”];

}

function Child1(){

    this.name = “child1”;

}

Child1.prototype = new Parent1();

Does this approach address the drawbacks of borrowing constructor inheritance? In the following code, we still add the sex attribute and say method to the prototype of the parent class:

Parent1.prototype. Sex = “male “;

Parent1.prototype.say = function() {

    console.log(” Oh,My God! “);

}

new Child1().sex; / / male

new Child1().say(); // Oh,My God!

This approach does address the disadvantage of borrowing constructor inheritance above.

However, there are still drawbacks to this approach. Let’s look at the following code:

var s1 = new Child1();

s1.colors.push(“black”);

var s2 = new Child1();

s1.colors; // (4) [“red”, “blue”, “yellow”, “balck”]

s2.colors; // (4) [“red”, “blue”, “yellow”, “balck”]

We instantiate two child1s, pushing a color in instance s1 for the colors attribute of the parent class, but s2 is changed as well. The reason for this is that the prototype objects in the prototype chain are shared.

This is not what we want, s1 and S2 objects should be isolated, which is the disadvantage of this inheritance approach.

Combinatorial inheritance

By composition, I mean both borrowing constructors and inheriting prototype chains.

function Parent2(){

    this.name = “parent2”;

    this.colors = [“red”,”blue”,”yellow”];

}

function Child2(){

    Parent2.call(this);

    this.type = “child2”;

}

Child2.prototype = new Parent2()

Notice on line 6 and 9 that this approach combines the advantages of borrowing constructor inheritance and stereotype chain inheritance. Does it solve the problem that the two instance objects are not isolated?

var s1 = new Child2();

s1.colors.push(“black”);

var s2 = new Child2();

s1.colors; // (4) [“red”, “blue”, “yellow”, “balck”]

s2.colors; // (3) [“red”, “blue”, “yellow”]

As you can see, s2 and S1 instance objects have been isolated.

But there are drawbacks to this approach. The constructor for the parent class is executed twice, first at child2.prototype = new Parent2() and then at instantiation time, which is not necessary.

Combinatorial inheritance optimization 1

Assign the parent class’s prototype object directly to the child class’s prototype object

function Parent3(){

    this.name = “parent3”;

    this.colors = [“red”,”blue”,”yellow”];

}

Parent3. Prototype. Sex = “male “;

Parent3.prototype. Say = function(){console.log(“Oh, My God!” )}

function Child3(){

    Parent3.call(this);

    this.type = “child3”;

}

Child3.prototype = Parent3.prototype;

var s1 = new Child3();

var s2 = new Child3();

console.log(s1, s2);

However, let’s look at the following code:

console.log(s1 instanceof Child3); // true

console.log(s1 instanceof Parent3); // true

As you can see, we cannot tell whether s1 is directly instantiated by Child3 or Parent3. Using the instanceof keyword to determine if it is an instanceof an object is basically useless.

We can also use. Constructor to see if an object is an instance of a class:

console.log(s1.constructor.name); // Parent3

As you can see, the constructor of S1 is a parent class, not a child class, which is clearly not what we want.

Combinatorial inheritance optimization ii

It’s the perfect way to inherit

function Parent4(){

    this.name = “parent4”;

    this.colors = [“red”,”blue”,”yellow”];

}

Parent4. Prototype. Sex = “male “;

Parent4.prototype.say = function(){console.log(“Oh, My God!” )}

function Child4(){

    Parent4.call(this);

    this.type = “child4”;

}

Child4. Prototype = Object. The create (Parent4. Prototype);

Child4.prototype.constructor = Child4;

Object.create is a way of creating an Object. It creates an intermediate Object

var p = {name: “p”}

var obj = Object.create(p)

// Object.create({ name: “p” })

By creating objects in this way, the prototype of the newly created object obj is P, and obj also has the property name, and the prototype object of the newly created intermediate object is its parameter.

This approach solves all of the above problems and is the perfect implementation of inheritance.

ES6 inherit

Classes can be inherited through the extends keyword, which is much cleaner and more convenient than ES5’s inheritance through modified prototype chains.

class Parent {

}

class Child1 extends Parent {

    constructor(x, y, colors) {

super(x, y); // Call parent constructor(x, y)

         this.colors = colors;

    }

    toString() {

return this.colors + ‘ ‘ + super.toString(); // Call the parent toString()

    }

}

In the above code, the super keyword appears in both the constructor and toString methods, where it represents the parent’s constructor, which is used to create a new parent’s this object.

Subclasses must call the super method from the constructor method or they will get an error when creating a new instance. If a subclass does not define a constructor method, that method is added by default; any subclass has a constructor method, regardless of whether it is explicitly defined.

ES5 inheritance essentially creates an instance object of the subclass, this, and then adds the Parent class’s methods to this (parent.apply (this)). ES6 has a completely different inheritance mechanism, essentially creating an instance object of the parent class, this (so the super method must be called first), and then modifying this with the constructor of the subclass.