• Inheritance


    Prototype Chaining

      Recall the relationship between consructors, prototypes and instances: each constructor has a prototype object that points back to the constructor, and instances have an internal pointer to the prototype. What if the prototype were actually an instance of another type? That would mean the prototype itself would have a pointer to a different prototype that, in turn, would have a pointer to another constructor. If that prototype were also an instance of another type, then the pattern would continue, forming a chain between instances and prototypes. This is the basic idea behind prototype chaining.

      Implement prototype chaining involves the following code pattern:

     1 function SuperType(){
     2     this.property = true;
     3 }
     4 
     5 SuperType.prototype.getSuperValue = function(){
     6     return this.property;
     7 }
     8 
     9 function SubType(){
    10     this.subproperty = false;
    11 }
    12 
    13 // inherit from SuperType
    14 SubType.prototype = new SuperType();
    15 
    16 SubType.prototype.getSubValue = function(){
    17     return this.subproperty;
    18 };
    19 
    20 var instance = new SubType();
    21 alert(instance.getSuperValue());                      // true
    View Code

    Problems with Prototype Chaining

      The major issue revolves around prototypes that contain reference values. When implementing inheritance using prototypes, the prototype actually becomes an instance of another type, meaning that what once were instance properties are now prototype properties. This issue is highlighted by the following example:

     1 function SuperType(){
     2     this.colors = ["red", "blue", "green"];
     3 }
     4 
     5 function SubType(){}
     6 
     7 // inherit from SuperType
     8 SubType.prototype = new SuperType();
     9 
    10 var instance1 = new SubType();
    11 instance1.colors.push("black");
    12 alert(instance1.colors);                          // "red, blue, green, black"
    13  
    14 var instance2 = new SubType();
    15 alert(instance2.colors);                          // "red, blue, green, black"
    View Code

    Constructor Stealing

      The basic idea is quite simple: call the supertype constructor from within the subtype constructor. Keeping in mind that functions are simple objects that execute code in a particular context, the apply() and call() methods can be used to execute a constructor on the newly created object, as in this example:

     1 function SuperType(name){
     2     this.name = name;
     3 }
     4 
     5 function SubType(){
     6     // inherit from SuperType passing in an argument
     7     SuperType.call(this, "Nicholas");
     8 
     9     // instance property
    10     this.age = 29;
    11 }
    12 
    13 var instance = new SubType();
    14 alert(instance.name);                     // "Nicholas"
    15 alert(instance.age);                        // 29
    View Code

     Problems with Constructor Stealing

      The downside to using constructor stealing exclusively is that it introduces the same problem as the constructor pattern for custom types: methods must be defined inside the constructor, so there's no function reuse. Furthermore, methods defined on the supertype's prototype are not accessible on the subtype, so all types can use only the constructor pattern. 

    Combination Inheritance

      The basic idea is to use prototype chaining to inherit properties and methods on the prototype and to use constructor stealing to inherit instance properties. This allows function reuse by defineing methods on the prototype and allows each instance to have its own properties. Consider the following: 

     1 function SuperType(name){
     2     this.name = name;
     3     this.colors = ["red", "blue", "green"];  
     4 }
     5 
     6 SuperType.prototype.sayName = function(){
     7     alert(this.name);
     8 };
     9 
    10 function SubType(name, age){
    11     SuperType.call(this, name);
    12     this.age = age;
    13 }
    14 
    15 SubType.prototype = new SuperType();
    16 
    17 SubType.prototype.sayAge = function(){
    18     alert(this.age);
    19 };
    20 
    21 var instance1 = new SubType("Nicholas", 29);
    22 instance1.color.push("black");
    23 alert(instance1.colors);           // "red, blue, green, black";
    24 instance1.sayName();               // "Nicholas";
    25 instance1.sayAge();                // 29;
    26 
    27 var instance2 = new SubType("Greg", 27);
    28 alert(instance2.colors);            // "red, blue, green";
    29 instance2.sayName();                // "Greg";
    30 instance2.sayAge();                 // 27
    View Code

    Prototypal inheritance

       Object.create() method accepts two arguments, an object to use as the prototype for a new object and an optional object defining additional properties to apply to the new object.

     1 var person = {
     2     name:  "Nicholas",
     3     friends:  ["Shelby", "Court", "Van"]  
     4 };
     5 
     6 var anotherPerson = Object.create(person, {
     7     name:  {
     8         value: "Greg"
     9     }
    10 });
    11 
    12 anotherPerson.friends.push("Rob");
    13 
    14 alert(anotherPerson.name);                       // "Greg"
    15 alert(anotherPerson.friends);                      // "Shelby, Court, Van, Rob"
    View Code

      Prototypal inheritance is useful when there is no need for the overhead of creating separate constructor, but you still need an object to behave similiarly to another. Keep in mind that properties containing reference values will always share those values, similar to using the prototype pattern.

    Parasitic Inheritance

      The idea behind parasitic inheritance is similar to that of the parasitic constructor and factory patterns: create a funciton that does the inheritance, augments the object in some way and then returns the objects as if it did all the work. The basic parasitic inheritance pattern looks like this:

    1 function createAnother(original){
    2     var clone = object(original);               // create a new object by calling a function
    3     clone.sayHi = function(){                  // augment the object in some way
    4         alert("hi");
    5     };
    6     return clone;                                  // return the object                 
    7 }
    View Code

      The createAnother() function can be used in the following way:

    1 var person = {
    2     name:  "Nicholas",
    3     friends:  ["Shelby", "Court", "Van"]
    4 };
    5 
    6 var anotherPerson = createAnother(person);
    7 anotherPerson.sayHi();                 // "hi"
    View Code

      The code in this example returns a new object based on person. The anotherPerson object has all of the properties and methods of person but adds a new method called sayHi().

      Parasitic inheritance is another pattern to use when you are concerned primarily with objects and not with custom types and constructors. Keep in mind that adding functions to objects using parasitic inheritance leads to inefficiencies related to function reuse, similar to the constructor pattern.

    Parasitic Combination Inheritance

      The most inefficient part of the Combination pattern is that the supertype constructor is always called twice: once to create the subtype's prototype, and once inside the subtype constructor. 

      Parasitic combination inheritance uses constructor stealing to inherit properties but uses a hybrid form of prototype chaining to inherit methods. The basic idea is this: instead of calling the supertype constructor to assign the subtype's prototype, all you need is a copy of the supertype's prototype. Essentially, use parasitic inheritance to inherit from the supertype's prototype and then assign the result to the subtype's prototype. The basic pattern for parastic combination inheritance is as follows:

    1 function inheritPrototype(SubType, SuperType){
    2     var prototype = object(SuperType.prototype);            // create object
    3     prototype.constructor = SubType;                              // augment object
    4     SubType.prototype = prototype;                                 // assign object  
    5 }
    View Code

      A call to inheritPrototype() can replace the subtype prototype assignment in the previous example, as shown here:

     1 function SuperType(name){
     2     this.name = name;
     3     this.colors = ["red", "blue", "green"];
     4 }
     5 
     6 SuperType.prototype.sayName = function(){
     7     alert(this.name);
     8 };
     9 
    10 function SubType(name, age){
    11     SuperType.call(this, name);
    12     this.age = age;
    13 }
    14 
    15 inheritPrototype(SubType, SuperType);
    16 
    17 SubType.prototype.sayAge = function(){
    18     alert(this.age);
    19 };
    View Code

      This example is more efficient in that the SuperType constructor is being called only one time, avoiding having unneccessary and unused properties on SubType.prototype. Furthermore, the prototype chain is kept intact, so both instanceof and isPrototypeOf() behave as they would normally. Parasitic combination inheritance is considered the most optimal inheritance paradigm for reference types.

  • 相关阅读:
    C# 使用DateTime.TryParseExact将自定义日期类型转换成日期
    ASP.NET WebServices 因 URL 意外地以“/HelloWorld”结束,请求格式无法识别。
    [UE4]计算2点坐标附近的坐标:线性插值法
    [UE4]Selector和Sequence的区别
    [UE4]蒙太奇动画运行时不播放,预览是好的
    [UE4]蓝图函数库小结
    [UE4]C++调用蓝图函数:BlueprintImplementableEvent函数说明符用法
    [UE4GamePlay架构(九)GameInstance(转)
    [UE4]C++取得蓝图控件实例
    [UE4]虚幻4的智能指针
  • 原文地址:https://www.cnblogs.com/linxd/p/4488381.html
Copyright © 2020-2023  润新知