javascript多级继承奇怪的结果

问题描述:

我刷新了我的javascript技能,并提出了一种方法,即对象可以从另一个继承。 继承应该是树状的。javascript多级继承奇怪的结果

Parent->Child->Child2

我已经延长了Function.prototype(不要告诉我这是一个坏主意,这可以在以后改变)

Function.prototype.extend = function(child) 
{ 
    // save child prototype 
    var childPrototype = child.prototype; 
    // copy parent to child prototype 
    child.prototype = Object.create(this.prototype); 
    // merge child prototype 
    for (var property in childPrototype) { 
     child.prototype[property] = childPrototype[property]; 
    } 
    child.prototype.constructor = child; 
    child.prototype.$parent = this.prototype; 
    return child; 
}; 

父对象:

var Parent = (function() 
{ 
    var Parent = function(x, y) 
    { 
     this.x = x; 
     this.y = y; 
     console.log('Parent constr', x, y); 
    } 

    Parent.prototype.move = function(x, y) 
    { 
     this.x += x; 
     this.y += y; 
     console.log('Parent moved.'); 
    }; 

    return Parent; 

}()); 

第一个孩子:

var Child = Parent.extend(function() 
{ 
    var Child = function(x, y) 
    { 
     this.$parent.constructor(x, y); 
     console.log('Child constr'); 
    } 

    Child.prototype.print = function() 
    { 
     console.log('Child print', this.x, this.y); 
    }; 

    // override 
    Child.prototype.move = function(x, y) 
    { 
     this.$parent.move(x, y); 
     console.log('Child moved.'); 
    }; 

    return Child; 

}()); 

老二:

var Child2 = Child.extend(function() 
{ 
    var Child2 = function(x, y) 
    { 
     this.$parent.constructor(x, y); 
     console.log('Child2 constr'); 
    } 

    // override 
    Child2.prototype.move = function(x, y) 
    { 
     this.$parent.move(x, y); // call parent move 
     console.log('Child2 moved.'); 
    }; 

    return Child2; 

}()); 

到目前为止,一切都很好。我可以调用父母的构造函数和方法,甚至覆盖方法。

var child = new Child2(1, 1); 
child.move(1, 1); 
child.print(); 

我获得以下输出这是正确的:

Parent constr 1 1 
Child constr 
Child2 constr 
Parent moved. 
Child moved. 
Child2 moved. 
Child print 2 2 

但如果我注释掉的第二个孩子的覆盖我获得以下的输出:

Parent constr 1 1 
Child constr 
Child2 constr 
Parent moved. 
Child moved. 
Child moved. -> WHY?? 
Child print 2 2 

我不明白为什么输出两次Child moved.。结果是正确的,但有些奇怪的事情正在发生。

编辑:

最后研究和跳水更进我想出了一个很好的解决方案后问题:

// call method from parent object 
Object.getPrototypeOf(Child2.prototype).move.apply(this, arguments); 

我又扩展到Function

Function.prototype.getParent = function() 
{ 
    return Object.getPrototypeOf(this.prototype); 
}; 

然后对例如Child2移动方法:

Child2.prototype.move = function(x, y) 
{   
    Child2.getParent().move.call(this, x, y); 
}; 

所以我不需要$parent了,我得到了预期的结果。

另一种解决方案是直接调用父原型:

Child2.prototype.move = function(x, y) 
{   
    Child.prototype.move.call(this, x, y); 
}; 
+0

它的多级继承不是多重的。 – C5H8NNaO4

+0

谢谢..我编辑了标题。 – bitWorking

+0

究竟你是什么部分“取消注释”?我没有看到任何代码被注释掉。 – apsillers

您应该使用适用于调用在正确的范围内的功能外,还采用this来访问父是不是安全。这实际上是学习JS调试的一个很好的问题,你可以看到使用断点发生的一切。

看你的第一个孩子:

// override 
Child.prototype.move = function(x, y) 
{ 
    this.$parent.move(x, y); 
    console.log('Child moved.'); 
}; 

当通过调用child.move(1,1)thischild达到了这个代码,哪些呢child.$parent.move点?为什么,在第一个孩子当然实施!

这第二次左右,this指向父的原型,所以现在我们很好。

那么这就是为什么这种情况正在发生,你能做些什么呢?嗯,这是你的,我提到的适用,因为那是我的默认以为,因此会使用this.$parent.move.apply(this, arguments);,但后来我们真的无法获得接受高等教育的父母,所以我能想到的唯一的其他选择是binding(拴马,任何道场人都可以阅读)每个函数都是相应的原型,从而保证其this的值总是指向相同的东西,因此它总是可以可靠地访问$父项。

当然,这将意味着实际的对象实例进不去,所以它只是纯粹的实用功能确实有用,但是这其实不是新的。如果您重写了print(它访问对象实例的x和y成员)并尝试调用父项,那么该项也会被打破。

+0

我以前用'this。$ parent.move.call(this,x,y)'试过了,'但是生成了一个*。 – bitWorking

+0

是的,因为你最终再次调用相同的函数,正如我所说的,这种技术可以让你访问实例对象,但没有更高的父母,所以只有一个继承级别可行。 –

+0

谢谢你,我接受你的答案,并给出一个解决方案,尽管我还没有找到答案。 – bitWorking

你的扩展方法高度继承的属性和方法的新对象的原型。它还创建一个$父对象,它等于父对象的原型。请注意,这会导致重复。第二个孩子有三个移动方法:

child.protoype.move 
child.$parent.move 
child.$parent.$parent.move 

即使您注释掉覆盖还有三种Move方法(虽然两者是同一个函数的引用)。

因此,当你运行孩子。移动你:

child.prototype.move它调用child.$parent.move它调用child.$parent.$parent.move

是child.prototype.move和儿童$ parent.move是同样的功能都引用并不妨碍他们执行两次的事实。