JavaScript summary 6.0—Detailed Explanation of Prototype Chain and Handwritten Inheritance

    Basic Concept

    Prototype

    Prototypes are properties of JavaScript functions. Every time a function is created in JavaScript, the JavaScript engine adds an extra property called prototype to the created function.
    _proto__ and constructor properties are unique to objects
    The prototype attribute is unique to function, because function is also a kind of object, so the function also has proto_ and constructor attributes
    The proto attribute of the object is equal to the prototype of the new constructor

    function foo() {
    }
    console.log(foo.prototype)  //foo {}
    
    var f1 = new foo()
    console.log(f1.__proto__ === foo.prototype) //true
    

    constructor property: a property added by default on the prototype object prototype, pointing to the object's constructor, all functions (the final constructor points to Function

    Prototypes allow objects to share properties and methods, simplifying the amount of code


    prototype chain

    A prototype chain is a chain that connects prototypes in sequence
    Each instance object (object) has a private attribute (called proto) pointing to the prototype object of its constructor (prototype). The prototype object also has a prototype object (proto) of its own, layering up until an object's prototype object is null. By definition, null has no prototype and acts as the last link in this prototype chain

    var obj = {}
    obj.__proto__ = {
    }
    // prototype chain
    obj.__proto__.__proto__ = { 
    }
    obj.__proto__.__proto__.__proto__ = {
     value: "3"
    }
    console.log(obj.value) //3
    

    Order when looking up object properties or methods: Search for the object itself --> search in the constructor of the object --> the prototype of the object (_proto_) --> the prototype of the constructor (prototype) ---> search in the prototype of the current prototype and so on until the prototype The top of the chain (Object.prototype), if it has not been found and the property to be searched for is undefined, and the method to be searched for is an error

    The prototype chain is searched up layer by layer, and the prototype of all objects can be traced back to Object in the end. At this time, there is no proto pointing to Object.prototype (top layer), so the prototype object at the top of the prototype chain is Object.prototype ( His proto value is null), there are many default properties and methods on this object

    var obj = {  }   
    console.log(obj.__proto__) //{}
    console.log(Object.prototype)//{}
    
    console.log(obj.__proto__.__proto__) //null
    console.log(Object.prototype.__proto__)//null
    


    Handwritten prototype chain inheritance

    1. Inheritance through the prototype chain

    Prototype chain inheritance is to directly let the prototype of the Child constructor directly point to the Parent object, so that the Parent's property Child object can be found directly from its prototype chain. Core: Child.prototype = new Parent(); //use prototype chain inheritance

    Parent class:

    // parent class: public properties and methods
    
    function Parent(name, age, friends) {
       //Attributes
       this.name = name || 'A';
       this.friends = friends || [];
       this.age = age || 18;
       //instance method
       this. say = function () {
     console.log(this.name + 'say hi');
       };
    }
    //prototype method
    Parent.prototype.eating = function() {
       console.log(this.name + "eating")
    }
    

    Subclass:

    // subclass: specific properties and methods
    function Child() {
       this.sno = 111
    }
    
    Child.prototype = new Parent(); //prototype chain inheritance
    Child.prototype.studying = function() {
       console.log(this.sno + 'studying');
    }
    
    var stu = new Child()
    console.log(stu.name) //'A'
    stu. eating() //A eating
    stu.studying()//111 studying
    //The subclass successfully inherits the properties and methods of the parent class, and successfully uses its own unique properties and methods
    

    shortcoming:

    //Create two stu objects
    var stu1 = new Child()
    var stu2 = new Child() 
    // Modify the value in the reference, different subcases will affect each other
    stu1. friends. push("B")
    
    console.log(stu1.friends) //B
    console.log(stu2.friends) //also B, not []
    
    // cannot pass parameters
    var stu3 = new Child("lilei", 112)
    
    • When creating a subclass instance, parameters cannot be passed to the parent class constructor
    • The reference properties from the prototype object are shared by all instances, so when multiple instances are created, if the modified object is a reference type, different instances will affect each other, because the two instances use the same prototype object


    2. Use constructor inheritance

    The principle is to use call in the Child constructor to change the point of this, which can realize passing parameters to the parent class, and there is no problem of mutual influence of reference attributes (no prototype is used) function Child(age) { Parent.call(this, age) }

    Parent class: the same as the parent class of the prototype chain

    Subclass:

    // can pass parameters
    function Child( name, age, friends) {
       Parent. call(this, name, age, friends);
    }
    
    var stu = new Child('AB', 20, ['lilei']);
    var stu1 = new Child('C', 18, ['li']);
      console.log(stu.name)//AB
    // Subclass instances will not affect each other
    stu.friends.push('lucy');
    console.log(stu.friends);//[ 'lilei', 'lucy' ]
    console.log(stu1.friends);//['li']
    //stu.eating() reports an error, the properties and methods on the prototype chain of the parent function cannot be inherited
    

    shortcoming:

    • Only the instance properties and methods of the parent class can be inherited, and the properties/methods on the prototype chain of the parent class cannot be inherited


    3. Composition inheritance

    Combined inheritance: You can inherit the properties/methods on the prototype chain of the parent class, which is to add the operation of the prototype of the subclass on the basis of inheritance using the constructor, and the constructor of the Parent will be executed once more function Child(age) { Parent.call(this, age) } Child.prototype = new Parent();

    Parent class: the same as the parent class of the prototype chain

    Subclass:

    function Child(name, age, friends) {
      Parent.call(this, name, age, friends);
    }
    Child.prototype = new Parent();
    
    var stu = new Child('AB', 20, ['lilei']);
     console.log(stu.name)//AB
    stu.eating() //AB eating
    

    shortcoming:

    • The parent class constructor (new Parent() and Parent.call()) is called twice, which consumes a little more memory (it feels negligible)
    • There will be two copies of properties in the supertype: one in the prototype object and one in the subtype instance (When we call the supertype.call(this, parameter) in the constructor of the subtype, the properties and methods in the supertype will be copied to the subtype. So **the supertype itself inside, we no longer need **)


    4. Inheritance through parasitic composition (most recommended)

    Parent class: the same as the parent class of the prototype chain

    Subclass:

    function Child(name, age, friends) {
       Parent. call(this, name, age, friends)
    }
    Child.prototype = Object.create(Parent.prototype)
    Child.prototype.constructor = Child
    //If you modify the prototype object in the form of an object, you need to use the constructor to point back to the original constructor, that is, repair the constructor
    
    var stu = new Child("F", 18, ["FX"])
    console.log(stu) //Parent { name: 'F', friends: [ 'FX' ], age: 18, say: [Function] }
    stu. eating()//F eating
    console.log(stu.constructor.name) //Child
    //If you don't point Child.prototype.constructor back to Child, the value here will be Parent
    
    
    /*Object.create() actually does two actions to create a new object, using the existing object as the prototype of the newly created object (prototype)*/
    /*
    Handwritten Object.create()
    Object.prototype.create = function (o) {
       function F() {}
       F.prototype = o;
       return new F();
    };
    */
    


    Summarize

    Each of these four handwriting inheritance methods appears to solve the shortcomings of the previous method. It is recommended to connect the four methods to think about learning when writing by hand.

    Popular posts from this blog

    大学资料分享——广工计院各个科目实验报告、课设及期末复习资料!!

    Win10 远程计算机或设备将不接受连接

    JAVA Traffic Signal Light Course Design (Source Code + Report + Video Demonstration)

    Implementation of Ajax Interceptor