我有3个班级:
class A{
DoStuff(){
return "Called from A";
}
}
class B extends A {
constructor(){
super();
var baseDoStuff = super.DoStuff;
this.DoStuff = function(){
return baseDoStuff() + " and Called from B";
}
}
}
class C extends B {
constructor(){
super();
var baseDoStufffff = super.DoStuff;
this.DoStuff = function(){
return baseDoStufffff() + " and Called from C";
}
}
}
我期望C级的DoStuff()调用B的DoStuff()(后者又会调用A)。
但是,在C上调用DoStuff()只返回“从A调用并从C调用”。我在这做错了什么?这不应该叫B的方法吗?
这方面的一个实例可以在这里找到:
答案 0 :(得分:11)
每当您需要使用super
时,请使用 方法 ,而不是 成员 :< / p>
class A{
DoStuff(){
return "Called from A";
}
}
class B extends A {
constructor(){
super();
}
DoStuff (){
return super.DoStuff() + " and Called from B";
}
}
class C extends B {
constructor(){
super();
}
DoStuff(){
return super.DoStuff() + " and Called from C";
}
}
var c = new C();
console.log(c.DoStuff());
Try it(打印从A调用,从B调用,从C调用)
这是因为super
转换为.prototype
,即super.DoStuff()
变为_super.prototype.DoStuff()
,.prototype
上唯一可用的内容就是类方法。
答案 1 :(得分:6)
JavaScript实际上没有方法。 TypeScript尝试用熟悉的符号隐藏prototype chain的工作方式,但是像所有抽象一样,它不完美。原型链的要点是,当你调用c.DoStuff()
时,它会在c实例上查找DoStuff,而不是原型(C),然后是原型(B),然后是原型(A),然后是原型(对象)。
这不仅适用于功能,也适用于您可能查找的任何成员。函数在JavaScript中并不是特别的,具有讽刺意味的是它们使它们变得强大。
在A类中使用TypeScript的语法,你在A的原型中放置了一个函数DoStuff。您调用DoStuff的每个A实例都会在实例中查找它(并且可能无法在那里找到它)查看原型并查看您定义的函数。到目前为止一切都很好。
然后你定义了一个扩展A的B类,因此原型链是B-> A-> Object。在B的构造函数中,您可以在每个实例上为DoStuff分配一个函数的新副本。 (这会占用更多的内存。)因此,当你构造一个新的B并在其上调用DoStuff时,那里有一个函数而没有检查原型。这样才有用。
现在定义一个C类扩展B,原型链是C-> B-> A-> Object。同样,C的每个实例都获得分配给DoStuff的函数的副本。但是在构造函数中我们没有从B的实例中获取DoStuff,我们从原型中获取它,并且我们没有将该函数直接添加到原型中。如果没有在那里找到它,我们将原型链上移到A.prototype并找到一个DoStuff成员从那里使用。这就是为什么C引用了A的DoStuff。
如果你做了类似的事情,你可以按照预期使你的代码工作:
class B extends A {
constructor() {
super();
}
}
B.prototype.DoStuff = function () {
return A.prototype.DoStuff() + " and Called from B";
}
但那只是愚蠢。