【问题标题】:Javascript Prototypal inheritance with Multiple Objects带有多个对象的 Javascript 原型继承
【发布时间】:2014-11-06 16:17:09
【问题描述】:

假设我有 5 个对象

Callback
Perishable
Object1
Object2
Object3

Object1 需要扩展 Callback 而不是 Perishable 对象,而 Object 2 应该扩展两者,Object 3 应该扩展 Perishable 但不是回调。

我知道这行得通...

Object1.prototype = new Callback();
Object3.prototype = new Perishable();

但是我该怎么做(我知道这行不通)

Object2.prototype = new Callback() && new Perishable();

【问题讨论】:

标签: javascript prototypal-inheritance


【解决方案1】:

如果你不想要任何外部依赖,你可以使用extend的这个实现:

function __extends(d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    var a = function(){}; a.prototype = new b();
    for (var p in a.prototype) d.prototype[p] = a.prototype[p];   
};

例子:

var animal = function(){

};

animal.prototype.run = function(){
     console.log("running");   
};

var feline = function(){

};

feline.prototype.hunt = function(){
     console.log("hunting");   
};

var cat = function(){

};

__extends(cat, animal);
__extends(cat, feline);

var scaryCat = new cat();

scaryCat.run();

scaryCat.hunt();

小提琴:http://jsfiddle.net/apqwf93a/9/

【讨论】:

  • 我仍然会使用 SLaks 帖子中的一些做法
【解决方案2】:

您可以使用extend function from Underscore.js library

代码如下所示:

_.extend(Object1.prototype, Callback.prototype);
_.extend(Object1.prototype, Perishable.prototype);

这是 JS 小提琴:http://jsfiddle.net/yb7kkh4e/2/

【讨论】:

    【解决方案3】:

    通常当您想要扩展多个对象时,您必须查看您的设计是否正确。对象是另一个对象吗?

    例如,猫是动物,猫可以移动。从 Movable 扩展 Cat 是错误的,因为 Cat 不是可以移动的 Movable,所以它应该实现 Movable 或保留 Movable 的默认实现。

    Cat Feline and Animal 的例子很好,但是不用多重继承也可以解决。猫是猫科动物,猫科动物是动物,所以猫没有理由既继承自猫科动物又继承动物动物,你可以让猫继承自猫科动物,而猫科动物继承自动物。

    选择的答案涉及混入(实现)的原型部分,但不包括如何初始化实例特定成员。以下是 following answer 的一部分:

    使用 mix ins 进行多重继承

    有些东西最好不要继承,如果 Cat 可以移动,而不是 Cat 不应该从 Movable 继承。猫不是可移动的,而是猫可以移动。在基于类的语言中,Cat 必须实现 Movable。在 JavaScript 中,我们可以在这里定义 Movable 并定义实现,Cat 可以覆盖、扩展它或者我们它的默认实现。

    对于 Movable,我们有特定于实例的成员(例如 location)。而且我们有不是特定于实例的成员(例如函数 move())。创建实例时,将通过调用 mxIns(由 mixin 辅助函数添加)来设置实例特定成员。原型成员将使用 mixin 辅助函数从 Movable.prototype 中的 Cat.prototype 上一一复制。

    var Mixin = function Mixin(args){
      var i, len;
      if(this.mixIns){
        i=-1;len=this.mixIns.length;
        while(++i<len){
            this.mixIns[i].call(this,args);
          }
      }  
    };
    Mixin.mix = function(constructor, mix){
      var thing
      ,cProto=constructor.prototype
      ,mProto=mix.prototype;
      //no extending, if multiple prototype uhs
      // have members with the same name then use
      // the last
      for(thing in mProto){
        if(Object.hasOwnProperty.call(mProto, thing)){
          cProto[thing]=mProto[thing];
        }
      }
      //instance intialisers
      cProto.mixIns = cProto.mixIns || [];
      cProto.mixIns.push(mix);
    };
    var Movable = function(args){
      args=args || {};
      //demo how to set defaults with truthy
      // not checking validaty
      this.location=args.location;
      this.isStuck = (args.isStuck===true);//defaults to false
      this.canMove = (args.canMove!==false);//defaults to true
      //speed defaults to 4
      this.speed = (args.speed===0)?0:(args.speed || 4);
    };
    Movable.prototype.move=function(){
      console.log('I am moving, default implementation.');
    };
    var Animal = function(args){
      args = args || {};
      this.name = args.name || "thing";
    };
    var Cat = function(args){
      Animal.call(args);
      //if an object can have others mixed in
      //  then this is needed to initialise 
      //  instance members
      Mixin.call(this,args);
    };
    Cat.prototype = Object.create(Animal.prototype);
    Cat.prototype.constructor = Cat;
    Mixin.mix(Cat,Movable);
    var poochie = new Cat({
      name:"poochie",
      location: {x:0,y:22}
    });
    poochie.move();
    

    【讨论】:

    • 老实说,我确实重新考虑了我的模型,并且确实更改了继承链。这仍然是一个非常好的主意,因为我真正需要它的时候是我重构并看到一堆共享代码的时候。我认为 mixins 在这些情况下确实更适合。现在虽然问题是它是什么。
    猜你喜欢
    • 2013-10-02
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2020-04-21
    • 2017-09-02
    • 1970-01-01
    相关资源
    最近更新 更多