Inheritance (JavaScript Advanced Programming Chapter 6 Core Knowledge Notes (2))

inherit

6.3.1 Prototype chain

Prototype chain as the main method of inheritance: the basic idea is to use the prototype to let one reference type inherit the properties and methods of another reference type

Insert picture description here

		function SuperType(){
    
    
            this.property = true;
        }
        
        SuperType.prototype.getSuperValue = function(){
    
    
            return this.property;
        };
        
        function SubType(){
    
    
            this.subproperty = false;
        }
        
        //inherit from SuperType
        SubType.prototype = new SuperType();
        
        SubType.prototype.getSubValue = function (){
    
    
            return this.subproperty;
        };
        
        var instance = new SubType();
        alert(instance.getSuperValue());   //true
       
        alert(instance instanceof Object);      //true
        alert(instance instanceof SuperType);   //true
        alert(instance instanceof SubType);     //true

        alert(Object.prototype.isPrototypeOf(instance));    //true
        alert(SuperType.prototype.isPrototypeOf(instance)); //true
        alert(SubType.prototype.isPrototypeOf(instance));   //true

The above code defines two constructors: SuperTypeand Subtype, each type has a property and a method, the main difference between them is SubTypeinheritance SuperType.

Inheritance is achieved by creating SuperTypean instance and assigning the instance to the SubType.prototyperealization.

The essence of implementation is to rewrite the prototype object and replace it with an instance of a new type. In other words, SuperTypethe properties and methods that originally existed in now also exist in SubType.prototype.

After establishing the inheritance relationship, we SubType.prototypeadded a method, so SuperTypethat a new method was added on the basis of the inherited properties and methods.

The end result is this:

instancePointed SubTypeprototype

SubTypePrototype and directed SuperTypeprototype

getSuperValue()Still in the SuperType.prototypemiddle, but propertyin the SubType.prototypemiddle. This is because it propertyis an instance property, but getSuperValue()a prototype method

  • Note: instance.constructorIt is now pointing to the SuperTypereason that this is because the original SubType.prototypeconstructor has been rewritten.

  • Determine the relationship between prototype and instance:

    1. instanceofOperator
    2. isPrototypeOf()method
  • Disadvantages of prototype chain inheritance:

    1. All instances of the child constructor will share the definition of the parent constructor 引用类型值属性.

      		function SuperType(){
              
              
                  this.colors = ["red", "blue", "green"];
              }
      
              function SubType(){
              
                          
              }
              
              //inherit from SuperType
              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"
      

      Our instance1.colorsamendments can be instance2.colorsreflected, which has fully proved this point.

    2. When creating an instance of a subtype, you cannot pass parameters to the supertype's constructor.

6.3.2 Borrowing constructor

In order to solve the problems caused by the inclusion of reference type values ​​in the prototype chain, developers began to use a technique called borrowed constructors.

  • The basic idea: call the supertype constructor inside the subtype constructor (the function is just an object that executes code in a specific environment, so the constructor can also be executed on the newly created object by using the apply() and call() methods.

    		function SuperType(){
          
          
                this.colors = ["red", "blue", "green"];
            }
    
            function SubType(){
          
            
                // inherit from SuperType
                // here, this will point to instance of SubType
                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"
    

    The background line in the code "seconded" the supertype constructor.

    By using the call()``和apply()method, we actually SubTypecall the SuperTypeconstructor in the environment of the newly created instance .

    In this way, all object initialization codes defined in the function will be SubTypeexecuted on the new object SuperType(), SubTypeand all instances of the result will have colorscopies of their own properties.

  • Pass parameters

    Compared with the prototype chain inheritance, borrowing the constructor has a big advantage. You can pass parameters to the supertype constructor in the subtype constructor.

            function SuperType(name){
          
          
                this.name = name;
            }
    
            function SubType(){
          
            
                //inherit from SuperType passing in an argument
                SuperType.call(this, "Nicholas");
                
                //instance property
                this.age = 29;
            }
    
            var instance = new SubType();
            alert(instance.name);    //"Nicholas";
            alert(instance.age);     //29
    
  • The problem of borrowing the constructor

    If you just borrow the constructor, then you cannot avoid the problem of the constructor mode. The methods are defined in the constructor, so there is no way to talk about function reuse.

    The methods defined in the prototype of the supertype are not visible to the subtype.

6.3.3 Combined inheritance

  • Combination inheritance refers to the combination of the prototype chain and the technology of borrowing constructors

  • Idea: Use the prototype chain to implement the inheritance of prototype properties and methods, and use the constructor to implement the inheritance of instance properties.

  • It not only realizes the reuse of functions by defining methods on the prototype, but also ensures that each instance has its own properties.

            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();       //27
    

    In this example, SuperTypetwo attributes are defined: nameand colors.

    SuperTypeThe prototype defines a method sayName().

    SubTypeThe constructor SuperTypepasses in nameparameters when calling the constructor , and then defines its own properties age.

    Then, assign SuperTypethe instance to SubTypethe prototype, and then define the method on the prototypesayAge()

    In this way, two different SubTypeinstances can both have their own attributes-including colorsattributes, and can use the same method.

  • Combinatorial inheritance avoids the defects of prototype chain and borrowed constructor inheritance, combines their advantages, and becomes the most commonly used inheritance mode in JavaScript.

  • instanceofAnd isPrototypeOfbe able to recognize objects created based on combined inheritance.

6.3.4 Prototype inheritance

Idea: With the help of prototypes, new objects can be created based on existing objects without having to create custom types.

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

Inside the object() function, a temporary constructor is created, and then the passed-in object is used as the prototype of the constructor, and finally a new instance of a temporary type is returned. Essentially, object() performs a shallow copy of the object passed in.

        function object(o){
    
    
            function F(){
    
    }
            F.prototype = o;
            return new F();
        }
        
        var person = {
    
    
            name: "Nicholas",
            friends: ["Shelby", "Court", "Van"]
        };
        
        var anotherPerson = object(person);
        anotherPerson.name = "Greg";
        anotherPerson.friends.push("Rob");
        
        var yetAnotherPerson = object(person);
        yetAnotherPerson.name = "Linda";
        yetAnotherPerson.friends.push("Barbie");
        
        alert(person.friends);   //"Shelby,Court,Van,Rob,Barbie"

6.3.5 Parasitic inheritance

  • Parasitic inheritance is an idea closely related to prototype inheritance

  • Idea: Create a function that is only used to encapsulate the inheritance process. The function internally enhances the object in a certain way, and finally returns the object as if it really did all the work.

    function createAnother(original) {
          
          
        var clone = object(original)  // 通过调用函数创建一个新对象
        clone.sayHi = function() {
          
              // 以某种方式来增强这个对象
            alert("hi")
        }
        return clone  // 返回这个对象
    }
    

6.3.6 Parasitic combined inheritance

Combinatorial inheritance is the most commonly used inheritance pattern in JavaScript, but it also has its own shortcomings. The biggest problem with combinatorial inheritance is that no matter what the situation is, the supertype constructor will be called twice: once when creating the subclass prototype, and the other time inside the subclass constructor.

        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); // 第二次调用SuperType()
            
            this.age = age;
        }

		// 继承方法
        SubType.prototype = new SuperType(); // 第一次调用 SuperType()
        SubType.prototype.constructor = SubType;
        SubType.prototype.sayAge = function(){
    
    
            alert(this.age);
        };

When you call the SuperType()function for the first time , SuperType.prototypeyou will get two properties: name, colors; They are both SuperTypeinstance properties, but they are now in SubTypethe prototype. When the SubTypeconstructor is called, the constructor is called again SuperType, this time creating instance attributes nameand on the new object colors. Therefore, this attribute blocks the two attributes with the same name in the prototype.

In other words, there are two sets of name and colors attributes: one set in the example and one set in the SubTypeprototype. This is SubTypethe result of calling the constructor twice .

Fortunately, we have found a way to solve this problem-parasitic combined inheritance.

  • Parasitic combined inheritance: inherit properties by borrowing constructors, and inherit methods through the hybrid form of the prototype chain

  • The basic idea: you don't have to call the supertype's constructor in order to specify the subtype's prototype. All we want is a copy of the supertype's prototype.

  • Essence: Use parasitic inheritance to inherit the prototype of the supertype, and then assign the result to the prototype of the subtype. The basic pattern of parasitic combined inheritance is as follows:

function inheritPrototype(subType, superType) {
    
    
    var prototype = object(superType.prototype) // 创建对象(超类型原型的一个副本)
    prototype.constructor = subType // 增强对象(为创建的副本添加constructor属性)
    subType.prototype = prototype // 指定对象
}
        function object(o){
    
    
            function F(){
    
    }
            F.prototype = o;
            return new F();
        }
    
        function inheritPrototype(subType, superType){
    
    
            var prototype = object(superType.prototype);   //create object
            prototype.constructor = subType;               //augment object
            subType.prototype = prototype;                 //assign object
        }
                                
        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);
        };
        
        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();       //27

The efficiency of this example is reflected in that it only calls the SuperTypeconstructor once , and therefore avoids SubType.prototypecreating unnecessary and redundant properties on it. At the same time, the prototype chain can remain unchanged; it can also be used instanceofandisPrototypeOf()

Guess you like

Origin blog.csdn.net/qq_27575925/article/details/111712955