2012-08-24 49 views
2

我对原型继承的概念比较陌生,所以也许这是原型继承应该如何工作,或者这只是javascript,但它似乎像原型继承只是很好的主要类型。例如我有以下代码:原型继承中的奇怪行为

var leg = { 
    type: null 
}; 

var Animal = { 
    traits: {}, 
    leg: Object.create(leg) 
}; 

var lion = Object.create(Animal); 
lion.traits.legs = 4; 
lion.leg.type = 'left'; 

var bird = Object.create(Animal); 
bird.traits.legs = 2; 
bird.leg.type = 'right'; 

alert(lion.traits.legs) // shows 2??? 
alert(lion.leg.type) // shows right??? 

最后两行显示我的困惑。这真的是原型继承应该如何工作,或者这只是如何实现它的JavaScript?

如果这确实是原型继承应该如何工作,那么我真的不明白这种类型的继承会是多么有用。如果我只能拥有原始类型,那么在创建复杂对象时似乎非常有限,因为有很多情况下我有一个对象存储另一个对象的实例。

+3

'traits'和'leg'对象被所有实例共享。只向应该共享的原型添加属性,所有*实例特有的*属于构造函数。 –

回答

2

不要继承非原始的状态。继承方法。使每个对象都有自己的状态。如果所有的对象都共享相同的状态,那么状态就是使对象唯一的东西,没有意义。

var Animal = { 
    method1: function() {}, 
    method2: function() {} 
}; 

var lion = Object.create(Animal, { 
    traits: { 
     value: {} 
    }, 
    leg: { 
     value: { 
      type: null 
     } 
    } 
}); 

var bird = Object.create(Animal, { 
    traits: { 
     value: {} 
    }, 
    leg: { 
     value: { 
      type: null 
     } 
    } 
}); 

顺便说一句,有做几乎同样的事情更详细和更好的支持的语法:

function Animal(traits, leg) { 
    this.traits = traits; 
    this.leg = leg; 
} 

var method = Animal.prototype; 

method.method1 = function() { 

}; 

method.method2 = function() { 

}; 


var lion = new Animal({}, {type: null}), 
    bird = new Animal({}, {type: null}); 
0

,这是它是如何工作的。属性traitsleg是在实例之间共享的可变对象。原型继承的想法是,除非明确地覆盖它,否则从原型继承所有状态。您不要覆盖字段traitleg,因此它们与原型共享。

这不同于基于类的继承,其中状态永远不会被继承,您必须初始化构造函数中的所有状态。

可以有复杂的对象,但是如果每个实例都需要有它自己的新对象字段实例,你必须在创建实例后创建它们,就像在构造函数中一样。

原型继承是非常有用的(相对于基于类的继承),因为:

  1. 您可以节省大量的内存,因为你只分配“槽”为这是从样机不同领域。在基于类的对象中,即使永远不会从默认值更改,也必须为所有字段分配空间。

  2. 很容易继承更改。例如。例如,如果你在UI框架中有一个“窗口”原型,并且有很多具体窗口从这个原型继承,你可以改变原型的颜色,并且它会自动继承到所有没有明确覆盖它的实例。