我在javascript中发现了这篇关于继承的帖子,我认为这是我在网上找到的最好的帖子之一,但这篇文章不能用于多重继承,因为它会覆盖过去Super Class的原型方法和变量
参考:Javascript inheritance: call super-constructor or use prototype chain?
我想知道是否有一种方法可以使用“代理构造函数”的原则进行多重继承(参见堆栈溢出引用帖子)。
我已经尝试过这种方法,我觉得它很有效,但我想了解有关限制的其他意见,如果有的话,关于这种实现。
你需要jQuery来运行它或者只是使用这个jsFiddle:http://jsfiddle.net/NGr2L/
Function.prototype.extend = function(p_parent){
function ctor() {};
//My trick for the Multiple Inheritance is to use the jQuery.extend method
ctor.prototype = $.extend({}, this.prototype, p_parent.prototype);
this.prototype = new ctor();
// I commentd this line of the reference post answer
//because it created multiple constructor which I found confusing
//this.prototype.constructor = this;
}
var Color = (function(){
//Constructor
function Color (p_color){
//Priviligied
this.color = p_color;
//Private
//...
};
//Public
Color.prototype.GetFormattedColor = function(){
return "I'm " + this.color;
};
return Color;
})();
var Animal = (function(){
//Constructor
function Animal (p_name){
//Priviligied
this.name = p_name;
//Private
//...
};
//Public
Animal.prototype.GetFormattedName = function(){
return "my name is " + this.name;
};
return Animal;
})();
var Tiger = (function(){
//Constructor
function Tiger (p_name, p_color, p_kindOfTiger){
//Base constructor
Color.call(this, p_color);
Animal.call(this, p_name);
//Priviligied
this.kindOfTiger = p_kindOfTiger;
//Private
//...
};
//Inheritance
Tiger.extend(Color); //I know, I could've loop
Tiger.extend(Animal);// on the "extend()" arguments to do this in one call
//Public
Tiger.prototype.GetTiger = function(){
return "I'm a " + this.kindOfTiger + ", " +
this.GetFormattedName() + " and " +
this.GetFormattedColor()
};
return Tiger;
})();
var myTiger = new Tiger("Boris", "Aqua", "bengal tiger");
myTiger.GetTiger();
非常感谢
答案 0 :(得分:1)
实现多重继承的最佳方法是组合。
假设我们有一个类Orange
,它扩展(继承自)类Fruit
和Color
。这两个类中的每一个都有自己的构造函数和方法。
多重继承的主要问题是父类中的方法可能会发生碰撞。
function Colour(shade) {
this.shade = shade;
}
Colour.prototype.describe = function() {
console.log('Colour of shade', this.shade);
}
function Fruit(type) {
this.type = type;
}
Fruit.prototype.describe = function() {
console.log('Fruit of type', this.type);
}
function Orange() {}
Orange.prototype.describe = function() {
this.constructor.describe(); // which describe to call?
console.log('Orange');
}
multipleExtend(Orange, [Fruit, Colour]);
为了避免命名空间冲突,最好的方法是使用组合而不是继承。
function Orange() {
this._colour = new Colour('orange');
this._fruit = new Fruit('orange');
}
Orange.prototype.describe = function() {
this._colour.describe();
this._fruit.describe();
console.log('Orange');
}
可以通过扩展一个类并组合另一个类来实现解决方案的折衷 - 但是要扩展哪些类以及要编写哪些类的选择可能不是实用。
PS:继承和扩展意味着同样的事情(防止可能的混淆)。
在JS中花了一些时间研究多重继承的想法之后,我想出了一个 design 来捕捉基本的想法。
不幸的是,我无法将所有内容都放在SO答案的大小中,所以我把它变成了an article。你会看到你的“代理构造函数”就是我所说的inheritsMultipleConstructors()
函数。
答案 1 :(得分:-1)
最合适方法的决定必须反映Color
,Animal
和Tiger
的关系。一只老虎显然是一种动物,动物和老虎都可能有一种颜色(虎有一种颜色)。因此继承仅适用于Animal <= Tiger
。可以通过组合获得Color
。但是这里聚合将是更有利的选择。因此,Tiger
类确实包含 color
类型的Color
字段。
基于真实类的多重继承(一次直接从多个原型继承)技术上在JS中是不可能的。但基于功能的组合 也是一个非常方便的工具。对于提供的示例,将会有两个额外的行为,这些行为不会意外地以describeThyself
方法名称为特征,这些名称已经被例如使用。一些类实现。因此,除了组成部分,行为还需要处理冲突解决。
出于舒适的原因,提供的示例代码确实具有类语法...
class Color {
constructor(colorValue) {
this.color = colorValue;
}
describeThyself() {
return `I'm colored ${this.color}.`;
}
}
class Animal {
constructor(speciesName) {
this.species = speciesName;
}
describeThyself() {
return `My species is called ${this.species}.`;
}
}
function withNormalHuntingBehavior() { // function based mixin.
function describeThyself() {
return 'I mostly feed on herbivorous mammals.';
}
if (this.describeThyself) { // - conflict resolution
this.describeThyself = (function (proceed) {
return function () { // - function composition
var result = proceed.apply(this/*, arguments*/);
return (result + ' ' + describeThyself.call(this/*, result, arguments*/));
}
}(this.describeThyself));
} else {
this.describeThyself = describeThyself;
}
return this;
}
function withManEatingBehavior() { // function based mixin.
function describeThyself() {
return 'I ocassionally kill and eat humans too.';
}
if (this.describeThyself) { // - conflict resolution
this.describeThyself = (function (proceed) {
return function () { // - function composition
var result = proceed.apply(this/*, arguments*/);
return (result + ' ' + describeThyself.call(this/*, result, arguments*/));
}
}(this.describeThyself));
} else {
this.describeThyself = describeThyself;
}
return this;
}
class Tiger extends Animal { // - inheritance part I.
constructor(subspeciesName, colorValue) {
super('Tiger'); // - inheritance part II.
this.subspecies = subspeciesName;
this.color = (new Color(colorValue)); // - aggregation.
}
describeThyself() {
return [
super.describeThyself.call(this), // - super delegation.
`I'm of the "${this.subspecies}" subspecies.`,
`And ${this.color.describeThyself()}` // - forwarding.
].join(' ');
}
}
// - composition at prototype level.
withNormalHuntingBehavior.call(Tiger.prototype);
function createBengalTiger(colorValue) { // bengal tiger factory
var
tiger = new Tiger('Bengal Tiger', colorValue);
// composition at instance level.
return withManEatingBehavior.call(tiger);
}
var siberianTiger = new Tiger('Siberian Tiger', 'kind of pale orange/reddish-something');
var bengalTiger = createBengalTiger("bright reddish-gold");
console.log('siberianTiger.describeThyself() : ' + siberianTiger.describeThyself());
console.log('bengalTiger.describeThyself() : ' + bengalTiger.describeThyself());
&#13;
.as-console-wrapper { max-height: 100%!important; top: 0; }
&#13;