Five inheritance methods of javaScript

Posted by jonnyw6969 on Fri, 24 Dec 2021 09:41:18 +0100

Portal
Supplement: prototype, prototype object, object prototype, prototype chain

Each constructor has a prototype prototype, which is just an object, so we often call it a prototype object. The role of prototype objects is to share

Each instance object also has a property called__ proto__ Or [[prototype]], because it is on the object, it is called "object prototype". Its purpose is to "point to the prototype object of the constructor"

When calling the properties and methods of an Object, js will first find out whether the current Object has the property. If not, it will continue to find the prototype (prototype Object). If the property has not been found, it will continue to find it until it reaches the Object. If it still does not find it, it will return undefined. This process is the prototype chain

Five methods of "inheritance" between objects.

Introduction: for example, there is now a constructor for an "animal" object.

function Animal(){
  this.species = "animal";
}
Animal.prototype.hair = "Yellow hair";
Animal.prototype.fly = function () {
     console.log("You sand sculpture wants to fly better!")
}

There is also a constructor for the "cat" object.

function Cat(name,color){
     this.name = name;
   this.color = color;
}

How can the cat inherit the animal?

1, Constructor binding

Introduction: the first method is also the simplest method. Use the call or apply method to bind the constructor of the parent object to the child object, that is, add a line in the constructor of the child object:

function Cat(name,color){
    Animal.apply(this, arguments);
    this.name = name;
    this.color = color;
}
var cat1 = new Cat("Big hair","yellow");
alert(cat1.species); // animal
// Try calling the prototype object method of Animal
console.log(bird1.hair); //undefined

Disadvantages: you cannot inherit the properties and methods of the Animal prototype object

2, prototype mode

Introduction: the second method is more common, using the prototype attribute. If the prototype object of "cat" points to an instance of Animal, all instances of "cat" can inherit Animal.

Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("Big hair","yellow");
alert(cat1.species); // animal

In the first line of the code, we point the prototype object of Cat to an instance of Animal.

Cat.prototype = new Animal();

It is equivalent to completely deleting the original value of the prototype object and giving it a new value. But what does the second line mean?

Cat.prototype.constructor = Cat;

It turns out that any prototype object has a constructor attribute that points to its constructor. If there is no "Cat.prototype = new Animal();" This line, Cat prototype. Constructor refers to Cat; After adding this line, Cat prototype. Constructor points to Animal.

alert(Cat.prototype.constructor == Animal); //true

More importantly, each instance also has a constructor attribute, which calls the constructor attribute of the prototype object by default.

alert(cat1.constructor == Cat.prototype.constructor); // true

Therefore, when running "Cat.prototype = new Animal();" After this line, CAT1 Constructor also points to Animal!

alert(cat1.constructor == Animal); // true

This will obviously lead to the disorder of the inheritance chain (cat1 is clearly generated by the constructor Cat), so we must manually correct it and change the constructor value of the Cat.prototype object to Cat. This is what the second line means.

This is a very important point, which must be observed when programming. This is followed below, that is, if the prototype object is replaced,

o.prototype = {};

Then, the next step must be to add the constructor attribute to the new prototype object and point this attribute back to the original constructor.

o.prototype.constructor = o;

3, Directly inherit prototype

Introduction: the third method is the improvement of the second method. Because in the Animal object, invariant attributes can be written directly to Animal prototype. Therefore, we can also let Cat() skip Animal() and directly inherit Animal prototype.

Now, let's rewrite the Animal object:

function Animal(){ }
Animal.prototype.species = "animal";

If this method is still adopted

function Animal(){
  this.species = "animals";
}

Cat is an attribute that cannot be inherited to species

console.log(cat1.species); // undefined

Then, connect the prototype object of Cat to the prototype object of Animal, and then complete the inheritance.

Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("Big hair","yellow");
alert(cat1.species); // animal

Compared with the previous method, this method has the advantages of high efficiency (no need to execute and create an instance of Animal) and memory saving. The disadvantage is that Cat.prototype and Animal.prototype now point to the same object, so any modification to Cat.prototype will be reflected in Animal.prototype.

Therefore, the above code is actually problematic. Look at the second line

Cat.prototype.constructor = Cat;

This sentence actually puts animal The constructor attribute of the prototype object has also been changed!

alert(Animal.prototype.constructor); // Cat

4, Using empty objects as mediators

Due to the above shortcomings of "direct inheritance prototype", there is a fourth method, using an empty object as an intermediary.

var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;

**F is an empty object, so it hardly takes up memory** At this time, modifying the prototype object of Cat will not affect the prototype object of Animal.

alert(Animal.prototype.constructor); // Animal

We encapsulate the above method into a function for easy use.

function extend(Child, Parent) {
    var F = function(){};
    // Point the prototype object of the empty object to the prototype object you want to inherit
    F.prototype = Parent.prototype;
   
    // Point the descendant prototype object to an instance object of an empty object
    Child.prototype = new F();
    
    // Modify the constructor of children 
    Child.prototype.constructor = Child;
    
    // See below
    Child.uber = Parent.prototype;
  }

When using, the method is as follows

extend(Cat,Animal);
var cat1 = new Cat("Big hair","yellow");
alert(cat1.species); // animal

This extend function is how the YUI library implements inheritance.

Also, to illustrate, the last line of the function body

  Child.uber = Parent.prototype;

It means to set a uber attribute for the child object, which directly points to the prototype attribute of the parent object. (uber is a German word, meaning "up" and "up.") this is equivalent to opening a channel on the child object to directly call the methods of the parent object. This line is placed here only to realize the completeness of inheritance. It is purely standby.

5, Copy inheritance

Introduction: the above uses prototype object to realize inheritance. We can also change our thinking and use the "copy" method to realize inheritance. In short, if all the properties and methods of the parent object are copied into the child object, can inheritance not also be realized? So we have a fifth way.

First, put all the invariant properties of Animal on its prototype object.

function Animal(){}
Animal.prototype.species = "animal";

Then, write a function to copy the attributes.

function extend2(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
      c[i] = p[i];
    }
    c.uber = p;
}

This function copies the attributes in the prototype object of the parent object to the prototype object of the Child object one by one.

When using, write this:

extend2(Cat, Animal);
var cat1 = new Cat("Big hair","yellow");
alert(cat1.species); // animal

Welcome to my personal blog

Topics: Javascript