preface

Interviewer: “Tell me everything you know about inheritance.” I was speechless… I have carried on the back obviously 😅, how to forget again, it seems that still have to come down to understand understanding (carry on the back not quite familiar) 😤, so I overnight put that book in the pile of the bottom of the nickname called the red book “Javascript advanced program design” to turn over.

Prototype chain

The relationship between prototypes and instances

The relationship between stereotype and instance: Each constructor has a stereotype object, which contains a pointer to the constructor, and each instance contains an internal pointer to the stereotype object

Can only say worthy of the classic book, a word to clear. This instance contains an internal pointer to the Prototype object that is actually [[Prototype]], which is available through Object.__proto__. Let’s print it out

 let obj = {}
 console.log(obj,obj.__proto__);
Copy the code

Then we put the Prototype of the constructor object to another instance constructor, this example also contains a pointer to the interior of the Prototype object [[Prototype]], we put the Prototype object to another another instance constructor, this example also contains the pointer to its Prototype object inside, so walk, It forms a chain of instances and prototypes.

Inheritance is implemented using prototype chains

Look at the code below

function SuperType(){
    this.color = ['red']}function SubType(){
    this.books = [The Little Red Book]
}


SubType.prototype = new SuperType

let obj1 = new SubType
let obj2 = new SubType
obj1.books.push('Rhino Book')
obj1.color.push('yellow')
console.log(obj2.books,obj2.color);    //['red'] ['red', 'yellow']
Copy the code

As you can see, the problem with inheritance based on prototype chains is that the parent class’s property is shared by all subclasses if it is a reference type. The reason is that new is involved. When we use the new keyword to create instances, we assign this to the object being created. Subtype. prototype = new SuperType = subtype.prototype. color = [‘ red book ‘] It is easy to understand why attributes of a parent class are shared by subclasses. So how to solve this problem? Clever programmers have come up with ways to borrow constructors 👊

Borrowing constructor

Take a look at this code:

function SuperType(name){
    this.color = ['red']
    this.name = name
}

function SubType(){
    SuperType.call(this.'Eating disorder')
    this.books = [The Little Red Book]}let obj1 = new SubType
let obj2 = new SubType
obj1.books.push('Rhino Book')
obj1.color.push('yellow')
console.log(obj2.books,obj2.color);         //[' Little Red Book '] ['red'
Copy the code

In the SubType constructor, we assign the subclass’s this pointer to the parent class using call, passing all the attributes of the parent class to the subclass and passing the parameters. The problem is that we don’t inherit functions from the superclass prototype. What if all functions are defined on properties? This is not a good idea because when we use the new keyword, we reallocate memory for each attribute, which causes a new function to be generated every time an instance is constructed. Ideally, if you define a function on a prototype, the function on a prototype will only be generated once, but to solve this problem we have to take a different approach.

Combination of inheritance

Consider the following code

function SuperType(name){
    this.color = ['red']
    this.name = name
}
SuperType.prototype.sayName = function(){
    console.log(this.name);
}
function SubType(){
    SuperType.call(this.'Eating disorder')
    this.books = [The Little Red Book]
}

SubType.prototype = new SuperType
SubType.prototype.constructor = SubType      
let obj2 = new SubType
obj2.sayName()           // Eating disorders
Copy the code

By assigning an instance of SuperType to the stereotype of SubType, creating a prototype chain, obj2 is able to call the functions of the superclass and pass the attributes of the superclass to the constructor of the subclass by borrowing the constructor. This makes this inheritance the most common inheritance pattern in Javascript. However, there is still a point we will talk about 😏 later. I don’t know if you noticed this line: SubType. The prototype. The constructor = SubType, when we were talking about the relationship between prototypes and instances have mentioned a prototype object contains a pointer to a constructor, Subtype. prototype = new SuperType overwrites this pointer, so we need to explicitly redirect to the constructor of the prototype object itself.

Primary inheritance

function object(o){
    function func(){}
    func.prototype = o
    return new func
}
Copy the code

Primitive inheritance creates an empty constructor, passes the object to be inherited, assigns the object to the constructor’s prototype, and returns an instance of the constructor

Parasitic inheritance

function create(o){
    let obj = object(o)
    obj.name = 'Eating disorder'
    return obj
}
Copy the code

Parasitic inheritance encapsulates the original object and enhances the returned instance. The drawback is that arguments in the object function still share reference types, like this:

function object(o){
    function Func(){}
    Func.prototype = o
    return new Func
}
function create(o){
    let obj = object(o)
    obj.name = 'Eating disorder'
    return obj
}
let o = {
    color: ['red'],}let obj1 = create(o)
let obj2 = create(o)
obj1.color.push('yellow')
console.log(obj2.color);      //[ 'red', 'yellow' ]
Copy the code

Parasitic combinatorial inheritance

We said in front of the modular inherit a little is not enough, because no matter how to combined inheritance will be called super types constructor twice, the first call to the parent class attribute assigned to a subclass constructor of the prototype, and these properties are not used, because the second call the superclass constructor will have the same properties to the subclass constructor, So attributes of the same name that were previously assigned to the stereotype of the subclass constructor are masked

function SuperType(){
    this.name = 'Eating disorder'
}
function SubType(){
    SuperType.call(this)    // Call the constructor a second time
}
SubType.prototype = new SuperType   // Call the constructor for the first time
SubType.prototype.constructor = SubType
let obj = new SubType 
Copy the code

There is an attribute name on the instance of the SubType constructor and the prototype object of the SubType.

function object(o){
    function Func(){}
    Func.prototype = o
    return new Func
}
function InheritPrototype(SubType,SuperType){
    let prototype = object(SuperType.prototype)
    prototype.constructor = SubType
    SubType.prototype = prototype
}
   
function SubType(){
    SuperType.call(this)    // Call the parent constructor
}
function SuperType(){}let obj = new SubType
Copy the code

The constructor of the parent class is called only once, and the object function is passed the supertype. prototype object of the parent class. Then the prototype object of the subclass points to the instance returned by Object. Can be said to be very clever 😆.

conclusion

Re-read the little Red Book inherit this part of the knowledge benefited a lot, the classic is a classic, every time browsing can learn different things, it can always use the most concise language to describe the logic of which, and I in front of the interviewer will only ah ah ah 😤