【问题标题】:JavaScript Inheritance [closed]JavaScript继承[关闭]
【发布时间】:2011-11-21 03:46:55
【问题描述】:

我正在尝试在 javascript 中实现继承。我想出了以下最少的代码来支持它。

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

专家,请让我知道这是否足够或我可能遗漏的任何其他重要问题。根据面临的类似问题,请提出其他更改建议。

这是完整的测试脚本:

function Base(){
    this.call = function(handler, args){
      handler.call(this, args);
    }
    this.superalert = function(){
        alert('tst');
    }
}

Base.extend = function(child, parent){
    parent.apply(child);
    child.base = new parent;
    child.base.child = child;
}

function Child(){
    Base.extend(this, Base);
    this.width = 20;
    this.height = 15;
    this.a = ['s',''];
    this.alert = function(){
        alert(this.a.length);
        alert(this.height);
    }
}

function Child1(){
    Base.extend(this, Child);
    this.depth = 'depth';
    this.height = 'h';
    this.alert = function(){
        alert(this.height); // display current object height
        alert(this.a.length); // display parents array length
        this.call(this.base.alert); 
          // explicit call to parent alert with current objects value
        this.call(this.base.superalert); 
          // explicit call to grandparent, parent does not have method 
        this.base.alert(); // call parent without overriding values
    }
}

var v = new Child1();
v.alert();
alert(v.height);
alert(v.depth);

【问题讨论】:

  • 如果你需要继承,有很多很多库已经提供了这个。至少阅读它们以找出您的代码错误的地方。但为什么要重新发明?我想到的两个很棒的 javascript 继承库是 klassselfish.js(我都用过,它们很棒。)
  • 我使用过 Klass,但是在覆盖数组变量时存在一些问题。我会尝试自私的。但我的版本是简单的 4 行代码,但在大多数情况下都适用于我。我只是想知道我以后是否会被这种方法卡住。
  • 您可能想查看this SO answer to a similar question;在所有伟大的技巧中,作者展示了如何在定义子类时删除对父构造函数的调用。
  • @hungryMind:如果您担心与您的代码有关的特定问题,为什么不编辑您的问题并准确告诉我们您害怕什么。因为您只是在询问您的代码是否正常,所以并​​没有给它太多的正义。你可能不会得到你正在寻找的答案。因此我建议你编辑你的 Q。

标签: javascript inheritance


【解决方案1】:

基本原型继承

在 JavaScript 中进行继承的一种简单但有效的方法是使用以下两行代码:

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

这类似于这样做:

B.prototype = new A();

两者的主要区别在于A的构造函数在使用Object.create时没有运行,这样更直观,更类似于基于类的继承。

在创建B 的新实例时,您始终可以选择运行A 的构造函数,方法是将其添加到B 的构造函数中:

function B(arg1, arg2) {
    A(arg1, arg2); // This is optional
}

如果要将B的所有参数传递给A,也可以使用Function.prototype.apply()

function B() {
    A.apply(this, arguments); // This is optional
}

如果你想将另一个对象混入B的构造函数链中,你可以将Object.createObject.assign结合起来:

B.prototype = Object.assign(Object.create(A.prototype), mixin.prototype);
B.prototype.constructor = B;

演示

function A(name) {
  this.name = name;
}

A.prototype = Object.create(Object.prototype);
A.prototype.constructor = A;

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

function mixin() {

}

mixin.prototype = Object.create(Object.prototype);
mixin.prototype.constructor = mixin;

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

C.prototype = Object.assign(Object.create(B.prototype), mixin.prototype);
C.prototype.constructor = C;

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());

创建自己的包装器

如果您不喜欢在整个代码中编写大致相同的两行代码,您可以编写一个基本的包装函数,如下所示:

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

这个包装器是如何工作的:

  1. 如果你传递一个参数,它的原型将继承自Object
  2. 如果您传递两个参数,第一个的原型将继承第二个的原型。
  3. 如果传递两个以上的参数,第一个的原型会继承第二个的原型,其他参数的原型会混入。

演示

function inheritance() {
  var args = Array.prototype.slice.call(arguments);
  var firstArg = args.shift();
  switch (args.length) {
  case 0:
    firstArg.prototype = Object.create(Object.prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  case 1:
    firstArg.prototype = Object.create(args[0].prototype);
    firstArg.prototype.constructor = firstArg;
    break;
  default:
    for(var i = 0; i < args.length; i++) {
      args[i] = args[i].prototype;
    }
    args[0] = Object.create(args[0]);
    var secondArg = args.shift();
    firstArg.prototype = Object.assign.apply(Object, args);
    firstArg.prototype.constructor = firstArg;
  }
}

function A(name) {
  this.name = name;
}

inheritance(A);

function B() {
  A.apply(this, arguments);
  this.street = "Downing Street 10";
}

inheritance(B, A);

function mixin() {

}

inheritance(mixin);

mixin.prototype.getProperties = function() {
  return {
    name: this.name,
    address: this.street,
    year: this.year
  };
};

function C() {
  B.apply(this, arguments);
  this.year = "2018"
}

inheritance(C, B, mixin);

var instance = new C("Frank");
console.log(instance);
console.log(instance.getProperties());

注意

Object.create 可以在所有现代浏览器中安全使用,包括 IE9+。 Object.assign 不适用于任何版本的 IE 或某些移动浏览器。如果您想使用它们并支持没有实现它们的浏览器,建议polyfill Object.create 和/或Object.assign

你可以找到 Object.create here 的 polyfill 一个用于Object.assign here

【讨论】:

    【解决方案2】:

    在玩 JS 对象时,我发现了一个更简约的解决方案 :-) 享受吧!

    function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); }
    

    例子

    function A() {
        this.info1 = function() {
            alert("A");
        }
    }
    
    function B(p1,p2) {
        extend(B,A,this);
        this.info2 = function() {
            alert("B"+p1+p2);
        }
    }
    
    function C(p) {
        extend(C,B,this,["1","2"]);
        this.info3 = function() {
            alert("C"+p);
        }
    }
    
    
    var c = new C("c");
    c.info1(); // A
    c.info2(); // B12
    c.info3(); // Cc
    

    【讨论】:

      【解决方案3】:

      这是我的解决方案,它基于Lorenzo Polidori'sanswer 中描述的标准原型继承方法。

      首先,我从定义这些帮助方法开始,这些方法使以后的事情更容易理解和阅读:

      Function.prototype.setSuperclass = function(target) {
          // Set a custom field for keeping track of the object's 'superclass'.
          this._superclass = target;
      
          // Set the internal [[Prototype]] of instances of this object to a new object
          // which inherits from the superclass's prototype.
          this.prototype = Object.create(this._superclass.prototype);
      
          // Correct the constructor attribute of this class's prototype
          this.prototype.constructor = this;
      };
      
      Function.prototype.getSuperclass = function(target) {
          // Easy way of finding out what a class inherits from
          return this._superclass;
      };
      
      Function.prototype.callSuper = function(target, methodName, args) {
          // If methodName is ommitted, call the constructor.
          if (arguments.length < 3) {
              return this.callSuperConstructor(arguments[0], arguments[1]);
          }
      
          // `args` is an empty array by default.
          if (args === undefined || args === null) args = [];
      
          var superclass = this.getSuperclass();
          if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
      
          var method = superclass.prototype[methodName];
          if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'");
      
          return method.apply(target, args);
      };
      
      Function.prototype.callSuperConstructor = function(target, args) {
          if (args === undefined || args === null) args = [];
      
          var superclass = this.getSuperclass();
          if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found.");
      
          return superclass.apply(target, args);
      };
      

      现在,你不仅可以用SubClass.setSuperclass(ParentClass)设置类的超类,还可以用SubClass.callSuper(this, 'functionName', [argument1, argument2...])调用被覆盖的方法:

      /**
       * Transform base class
       */
      function Transform() {
          this.type = "2d";
      }
      
      Transform.prototype.toString = function() {
          return "Transform";
      }
      
      /**
       * Translation class.
       */
      function Translation(x, y) {
          // Parent constructor
          Translation.callSuper(this, arguments);
      
          // Public properties
          this.x = x;
          this.y = y;
      }
      // Inheritance
      Translation.setSuperclass(Transform);
      
      // Override
      Translation.prototype.toString = function() {
          return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y;
      }
      
      /**
       * Rotation class.
       */
      function Rotation(angle) {
          // Parent constructor
          Rotation.callSuper(this, arguments);
      
          // Public properties
          this.angle = angle;
      }
      // Inheritance
      Rotation.setSuperclass(Transform);
      
      // Override
      Rotation.prototype.toString = function() {
          return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle;
      }
      
      // Tests
      translation = new Translation(10, 15);
      
      console.log(translation instanceof Transform); // true
      console.log(translation instanceof Translation); // true
      console.log(translation instanceof Rotation); // false
      
      console.log(translation.toString()) // Transform2d Translation 10:15
      

      诚然,即使使用辅助函数,这里的语法也很尴尬。不过值得庆幸的是,在 ECMAScript 6 中添加了一些语法糖 (maximally minimal classes) 以使事情变得更漂亮。例如:

      /**
       * Transform base class
       */
      class Transform {
        constructor() {
          this.type = "2d";
        }
      
        toString() {
          return "Transform";
        } 
      }
      
      /**
       * Translation class.
       */
      class Translation extends Transform {
        constructor(x, y) {
          super(); // Parent constructor
      
          // Public properties
          this.x = x;
          this.y = y;
        }
      
        toString() {
          return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y;
        }
      }
      
      /**
       * Rotation class.
       */
      class Rotation extends Transform {
        constructor(angle) {
          // Parent constructor
          super(...arguments);
      
          // Public properties
          this.angle = angle;
        }
      
        toString() {
          return super(...arguments) + this.type + " Rotation " + this.angle;
        }
      }
      
      // Tests
      translation = new Translation(10, 15);
      
      console.log(translation instanceof Transform); // true
      console.log(translation instanceof Translation); // true
      console.log(translation instanceof Rotation); // false
      
      console.log(translation.toString()) // Transform2d Translation 10:15
      

      请注意,ECMAScript 6 目前仍处于草稿阶段,据我所知,尚未在任何主要的 Web 浏览器中实现。但是,如果您愿意,可以使用 Traceur compiler 之类的东西将 ECMAScript 6 编译成普通的旧的基于 ECMAScript 5 的 JavaScript。可以看到上面使用 Traceur 编译的例子here

      【讨论】:

        【解决方案4】:

        要在ECMAScript 5 中实现javascript 继承,您可以定义对象的原型并使用Object.create 进行继承。您还可以根据需要添加/覆盖属性。

        例子:

        /**
         * Transform base class
         */
        function Transform() {
            this.type = "2d";
        }
        
        Transform.prototype.toString = function() {
            return "Transform";
        }
        
        /**
         * Translation class.
         */
        function Translation(x, y) {
            // Parent constructor
            Transform.call(this);
        
            // Public properties
            this.x = x;
            this.y = y;
        }
        
        // Inheritance
        Translation.prototype = Object.create(Transform.prototype);
        
        // Override
        Translation.prototype.toString = function() {
            return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y;
        }
        
        /**
         * Rotation class.
         */
        function Rotation(angle) {
            // Parent constructor
            Transform.call(this);
        
            // Public properties
            this.angle = angle;
        }
        
        // Inheritance
        Rotation.prototype = Object.create(Transform.prototype);
        
        // Override
        Rotation.prototype.toString = function() {
            return Transform.prototype.toString() + this.type + " Rotation " + this.angle;
        }
        
        // Tests
        translation = new Translation(10, 15);
        
        console.log(translation instanceof Transform); // true
        console.log(translation instanceof Translation); // true
        console.log(translation instanceof Rotation); // false
        
        console.log(translation.toString()) // Transform2d Translation 10:15
        

        【讨论】:

        • Translation.prototype = Object.create(new Transform()); ? Translation.prototype = Object.create(Transform.prototype);
        • @4esn0k 是的,谢谢。
        • 为什么不只是Translation.prototype = new Transform()?另外,由于答案目前不起作用,您会编辑它吗?
        • @JörnZaefferer 看看这里:stackoverflow.com/q/4166616/885464。 '答案目前不起作用'是什么意思?
        • 您还应该明确设置子类的构造函数:Translation.prototype.constructor = Translation。用于克隆对象(在大多数技术中)。
        【解决方案5】:

        这个简单的方法怎么样

            function Body(){
                this.Eyes = 2;
                this.Arms = 2;
                this.Legs = 2;
                this.Heart = 1;
                this.Walk = function(){alert(this.FirstName + ' Is Walking')};
            }
        
            function BasePerson() {
                var BaseBody = new Body(this);
                BaseBody.FirstName = '';
                BaseBody.LastName = '';
                BaseBody.Email = '';
                BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); };
                return BaseBody;
            }
        
            function Person(FirstName,LastName)
            {
                var PersonBuild = new BasePerson();
                PersonBuild.FirstName = FirstName;
                PersonBuild.LastName = LastName;
                return PersonBuild;
            }
        
            var Person1 = new Person('Code', 'Master');
            Person1.IntroduceSelf();
            Person1.Walk();
        

        【讨论】:

          【解决方案6】:

          我找到了一个比扩展和原型设计更容易的解决方案。实际上,我不知道它的效率如何,尽管它看起来很干净而且很实用。

          var A = function (p) {
              if (p == null) p = this;
              p.a1 = 0;
              this.a2 = 0;
              var a3 = 0;
          };
          
          var B = function (p) {
              if (p == null) p = this;
              p.b1 = new A(this);
              this.b2 = new A(this);
              var b3 = new A(this);
              this b4 = new A();
          };
          
          var a = new A ();
          var b = new B ();
          

          结果:

          a
              a1        0
              a2        0
          b
              a1        0
              b1
                  a2    0
              b2
                  a2    0
              b4
                  a1    0
                  a2    0
          

          实际例子:

          var Point = function (p) {
              if (p == null) p = this;
              var x = 0;
              var y = 0;
              p.getPoint = function () { return [x,y]; };
              p.setPoint = function (_x,_y) { x = _x; y = _y; };
          };
          
          var Dimension = function (p) {
              if (p == null) p = this;
              var w = 0;
              var h = 0;
              p.getDimension = function() { return [w,h] };
              p.setDimension = function(_w,_h) { w = _w; h = _h };
          };
          
          var Rect = function (p) {
              if (p == null) p = this;
              var dimension = new Dimension(this);
              var location  = new Point(this);
          };
          
          var rect = new Rect ();
          rect.setDimension({w:30,h:40});
          rect.setPoint({x:50,y:50});
          

          【讨论】:

            【解决方案7】:

            使用AWeb library 的最简单方法。官方样本:

               /**
                 * A-class
                 */
               var ClassA = AWeb.class({
                 public : {
                    /**
                      * A-class constructor
                      */
                    constructor : function() {
                       /* Private variable */
                       this.variable1 = "A";
                       this.calls = 0;
                    },
            
                    /**
                      * Function returns information about the object
                      */
                    getInfo : function() {
                       this.incCalls();
            
                       return "name=" + this.variable1 + ", calls=" + this.calls;
                    }
                 },
                 private : {
                    /**
                      * Private function
                      */
                    incCalls : function() {
                       this.calls++;
                    }
                 }
              });
              /**
                * B-class
                */
              var ClassB = AWeb.class({
                 extends : ClassA,
                 public : {
                    /**
                      * B-class constructor
                      */
                    constructor : function() {
                       this.super();
            
                       /* Private variable */
                       this.variable1 = "B";
                    },
            
                    /**
                      * Function returns extended information about the object
                      */
                    getLongInfo : function() {
                       return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined";
                    }
                 }
              });
              /**
                * Main project function
                */
              function main() {
                 var a = new ClassA(),
                     b = new ClassB();
            
                 alert(
                    "a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" +
                    "a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" +
            
                    "b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" +
                    "b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" +
            
                    "b.getInfo()=" + b.getInfo() + "\n" +
                    "b.getLongInfo()=" + b.getLongInfo()
                 );
              }
            

            【讨论】:

              【解决方案8】:
              //
              //  try this one:
              //  
              //    function ParentConstructor() {}
              //    function ChildConstructor()  {}
              //
              //    var 
              //        SubClass = ChildConstructor.xtendz( ParentConstructor );
              //
              Function.prototype.xtendz = function ( SuperCtorFn ) {
              
                  return ( function( Super, _slice ) {
              
                              // 'freeze' host fn 
                              var
                                  baseFn = this, 
                                  SubClassCtorFn;
              
                              // define child ctor
                              SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) {
              
                                  // execute parent ctor fn on host object
                                  // pass it last ( array ) argument as parameters
                                  Super.apply( this, _slice.call( arguments, -1 )[0] );
              
                                  // execute child ctor fn on host object
                                  // pass remaining arguments as parameters
                                  baseFn.apply( this, _slice.call( arguments, 0, -1 ) );
              
                              };
              
                              // establish proper prototype inheritance
                              // 'inherit' methods
                              SubClassCtorFn.prototype = new Super;
              
                              // (re)establish child ctor ( instead of Super ctor )
                              SubClassCtorFn.prototype.constructor = SubClassCtorFn;
              
                              // return built ctor
                              return SubClassCtorFn;
              
                  } ).call( this, SuperCtorFn, Array.prototype.slice );
              };
              
              // declare parent ctor
              function Sup( x1, x2 ) {
                  this.parent_property_1 = x1;
                  this.parent_property_2 = x2;
              }
              
              // define some methods on parent
              Sup.prototype.hello = function(){ 
                 alert(' ~  h e l l o   t h e r e  ~ ');
              };
              
              
              // declare child ctor
              function Sub( x1, x2 ) {
                  this.child_property_1 = x1;
                  this.child_property_2 = x2;
              }
              
              var
                  SubClass = Sub.xtendz(Sup), // get 'child class' ctor
                  obj;
              
              // reserve last array argument for parent ctor
              obj = new SubClass( 97, 98, [99, 100] ); 
              
              obj.hello();
              
              console.log( obj );
              console.log('obj instanceof SubClass      -> ', obj instanceof SubClass      );
              console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass );
              console.log('obj instanceof Sup           -> ', obj instanceof Sup           );
              console.log('obj instanceof Object        -> ', obj instanceof Object        );
              
              //
              //  Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98}
              //  obj instanceof SubClass      -> true
              //  obj.constructor === SubClass -> true
              //  obj instanceof Sup           -> true
              //  obj instanceof Object        -> true
              //
              

              【讨论】:

                【解决方案9】:

                为什么不使用对象而不是函数:

                var Base = {
                    superalert : function() {
                        alert('tst');
                    }
                };
                
                var Child = Object.create(Base);
                Child.width = 20;
                Child.height = 15;
                Child.a = ['s',''];
                Child.childAlert = function () {
                        alert(this.a.length);
                        alert(this.height);
                    }
                
                var Child1 = Object.create(Child);
                Child1.depth = 'depth';
                Child1.height = 'h';
                Child1.alert = function () {
                    alert(this.height);
                    alert(this.a.length);
                    this.childAlert();
                    this.superalert();
                };
                

                然后这样称呼它:

                var child1 = Object.create(Child1);
                child1.alert();
                

                这种方法比函数更简洁。 我发现这个博客解释了为什么在 JS 中使用函数继承不是一种正确的方法:http://davidwalsh.name/javascript-objects-deconstruction

                编辑

                var Child也可以写成:

                var Child = Object.create(Base, {
                    width : {value : 20},
                    height  : {value : 15, writable: true},
                    a : {value : ['s', ''], writable: true},
                    childAlert : {value : function () {
                        alert(this.a.length);
                        alert(this.height);
                    }}
                });
                

                【讨论】:

                  【解决方案10】:
                  //This is an example of how to override a method, while preserving access to the original.
                  //The pattern used is actually quite simple using JavaScripts ability to define closures:
                  
                      this.somefunction = this.someFunction.override(function(args){
                          var result = this.inherited(args);
                          result += this.doSomethingElse();
                          return result;
                      });
                  
                  //It is accomplished through this piece of code (courtesy of Poul Krogh):
                  
                  /***************************************************************
                      function.override overrides a defined method with a new one, 
                      while preserving the old method.
                      The old method is only accessible from the new one.
                      Use this.inherited() to access the old method.
                  ***************************************************************/
                  
                      Function.prototype.override = function(func)
                      {
                          var remember = this;
                          var f = function() 
                          {
                               var save = this.inherited; 
                               this.inherited = remember;
                               var result = func.apply(this, Array.prototype.slice.call(arguments));
                               this.inherited = save;
                               return result;
                          };
                          return f;
                      }
                  

                  【讨论】:

                    【解决方案11】:

                    虽然我同意上述所有答案,但我认为 JavaScript 不必是面向对象的(避免继承),而 an object-based approach 在大多数情况下就足够了。

                    我喜欢 Eloquent JavaScript 在面向对象编程上谈论 OO 时开始其 Chapter 8 的方式。与其解读实现继承的最佳方式,不如将更多的精力投入到学习 JavaScript 的函数方面,因此,我发现函数式编程的 Chapter 6 更有趣。

                    【讨论】:

                      【解决方案12】:

                      这里是最简单的,我希望是最简单的方式来理解 JS 中的继承。这个例子对 PHP 程序员最有帮助。

                      function Mother(){
                          this.canSwim = function(){
                              console.log('yes');
                          }
                      }
                      
                      function Son(){};
                      Son.prototype = new Mother;
                      Son.prototype.canRun = function(){
                          console.log('yes');
                      }
                      

                      现在儿子有一个被覆盖的方法和一个新的

                      function Grandson(){}
                      Grandson.prototype = new Son;
                      Grandson.prototype.canPlayPiano = function(){
                          console.log('yes');
                      };
                      Grandson.prototype.canSwim = function(){
                          console.log('no');
                      }
                      

                      现在孙子有两个被覆盖的方法和一个新的

                      var g = new Grandson;
                      g.canRun(); // => yes
                      g.canPlayPiano(); // => yes
                      g.canSwim(); // => no
                      

                      【讨论】:

                      【解决方案13】:

                      我认为 Crockfords 的解决方案过于复杂,John 的也是如此。获得 javascript 继承比他们似乎描述的要简单得多。考虑:

                      //Classes
                      function A() {
                          B.call(this);
                      }
                      
                      function B() {
                          C.call(this);
                          this.bbb = function() {
                              console.log("i was inherited from b!");
                          }
                      }
                      
                      function C() {
                          D.call(this);
                      }
                      
                      function D() {
                          E.call(this);
                      }
                      
                      function E() {
                          //instance property 
                          this.id = Math.random()
                      }
                      
                      //set up the inheritance chain (order matters) 
                      D.prototype = new E();
                      C.prototype = new D();
                      B.prototype = new C();
                      A.prototype = new B();
                      
                      //Add custom functions to each
                      A.prototype.foo = function() {
                          console.log("a");
                      };
                      B.prototype.bar = function() {
                          console.log("b");
                      };
                      C.prototype.baz = function() {
                          console.log("c");
                      };
                      D.prototype.wee = function() {
                          console.log("d");
                      };
                      E.prototype.woo = function() {
                          console.log("e");
                      };
                      
                      //Some tests
                      a = new A();
                      a.foo();
                      a.bar();
                      a.baz();
                      a.wee();
                      a.woo();
                      console.log(a.id);
                      a.bbb();
                      console.log(a instanceof A);
                      console.log(a instanceof B);
                      console.log(a instanceof C);
                      console.log(a instanceof D);
                      console.log(a instanceof E);​
                      var b = new B();
                      console.log(b.id)
                      

                      我已经在my blog 上写了上述解决方案的完整描述。

                      【讨论】:

                      • 除了只支持所有公众会员
                      • @rodrigo-silveira,不确定你的意思。如果你想要私有,你只需用 var x = "whatever" 声明它们,不是吗?
                      • 我认为@rodrigo-silveira 的意思是它不支持受保护的成员,这两种解决方案都不支持。 (根据定义,私有成员不能从子类访问,因此没有意义)。您必须使用 this._myProtectedVariable = 5; 之类的东西来创建受保护的成员。
                      • 非常好的解决方案,只有(轻微的)缺点,构造函数执行了两次。一次 D.call(this),又一次:new D()。这通常不是什么大问题,但如果你确实想避免它,你可以像这样使用 Object.create:而不是 C.prototype = new D();你可以写 C.prototype = Object.create(D.prototype);例如:jsfiddle.net/9Dxkb/1
                      • 最后,一个有效的非混淆解释!我颠倒了你的逻辑,使 E 反向继承(E 最多),因为这对我来说很有意义。谢谢!
                      猜你喜欢
                      • 2012-12-02
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多