2016-04-28 69 views
5

我有这两个打字稿类:打字稿覆盖类的方法,这

class Base { 
    value: string; 

    lambdaExample =() => { 
    this.value = 'one'; 
    } 

    methodExample() { 
    this.value = 'two'; 
    } 
} 

class Child extends Base { 
    lambdaExample =() => { 
    super.lambdaExample(); // Error, because I've overwritten (instead of overridden) the method 
    this.value = 'three'; // ok 
    } 

    methodExample() => { 
    super.methodExample(); // ok 
    this.value = 'four'; // Error: this refers to window, not to the actual this 
    } 
} 

我怎样写我的方法,这样的方式this引用是可靠的,我可以重写方法和调用它们父类?

+0

可能重复的[在打字稿中调用超类的重写方法](http://stackoverflow.com/questions/30819663/call-an-overridden-method-from-super-class-in-typescript) – smnbbrv

+1

这是不是重复的:该问题是关于在构造函数中调用类方法,而不是关于使用类属性的重写方法。 – Jorn

+0

@smnbbrv这个问题与此无关。 –

回答

2

实际上,在Microsoft's Git Wiki上处理这个问题的方法很好看。它基本上归结为:

  • 如果您关心继承,每次从不同的上下文调用方法时绑定或包装该方法。
  • 将方法转换为包含函数的属性(如果不包含)。

在实际的维基中还有很多规定,我真的建议你阅读整个事情。

编辑

包装的一个例子:

鉴于类

class SomeClass { 
    public someProp: string = "Hello World"; 

    public someMethod() { 
     console.log(this.someProp); 
    } 

} 

如果你要调用someMethod从(例如)单击处理 - someEl.onclick = instanceOfMyClass.someMethod; - 一个例外(假设window没有财产someProp )。

您可以通过函数或者结合instanceOfMyClass(不是类型安全的,不ES6兼容)或者通过手动包装它(实际上什么绑定是干什么的,反正)规避这样的:

someEl.onclick = function() { 
    someInstanceOfMyClass.someMethod(); 
}; 

这是一个小有点冗长和迂腐,但通过调用someMethod作为someInstanceOfMyClass的属性,而不是将它传递给事件处理程序(将其变成window的属性),则确保this始终是MyClass的实例。

+0

我对包装方法略有不清楚。会有这样的工作吗? 'class Child {methodExample(){var wrap =()=> {super.methodExample()};包(); }' – Jorn

+0

所以包装类似于绑定,因为每次从不同的上下文调用函数时都会这样做。例如,给定class class MyClass {public someMethod(){console.log(this); }}''从另一个上下文中获取'this'作为'MyClass'的一个实例,你可以这样调用它:'(()=> {instanceOfMyClass.someMethod()})()'。重要的是,我们将方法称为'instanceOfMyClass'的属性,而不是直接传递它(从而更改其上下文)。 –

1

你对错误原因的假设是错误的,我认为这是你问题的原因......至少据我了解。

lambdaExample =() => { 
    this.value = 'one'; 
} 

此线,例如是定义上Base一个属性,而不是一个方法,并且不能重写的属性。您在Base中定义的唯一实例方法是methodExample

Child中,您正在为lambaExample分配一个新变量。您拨打super.lambaExample()失败,因为只能通过super()访问方法;访问属性通过this完成。您的Child类中的methodExample对我来说显示为语法错误。

请注意,您仍然可以在覆盖的lambaExample属性中调用超级Child,但只能在方法上调用。这工作:

lambdaExample =() => { 
    super.methodExample(); // Success on super.<somemethod>() 
    this.value = 'three'; 
} 

我只知道的声明在一个类的实例方法的一种方式,如果你是与语法一致,this作品如你所愿:

class Base { 
    value: string; 

    lambdaExample() { 
    this.value = 'one'; 
    } 

    methodExample() { 
    this.value = 'two'; 
    } 
} 

class Child extends Base { 
    lambdaExample() { 
    super.lambdaExample(); 
    this.value = 'three'; 
    } 

    methodExample() { 
    super.methodExample(); 
    this.value = 'four'; 
    } 
} 
+0

我可以按照你的整个帖子直到最后一句:在方法的例子中,'this'不能按预期工作,正如问题中所解释的那样。在这种情况下,'super'调用起作用,但'this.value'引用是'undefined'。 – Jorn

+0

@Jorn - 直到您将其设置为一个值时才会定义它,只有在调用lambdaExample或methodExample时才会执行此操作。 –

1

我已经找到了解决办法,但它的丑陋:

class Base { 
    someFunction =() => { 
    this.otherFunction(); 
    } 
    protected otherFunction =() => { 
    // actual implementation here 
    } 
} 
class Child { 
    someFunction =() => { 
    this.otherFunction(); 
    // additional implementation here 
    } 
} 

这样,您就可以拨打someFunction在任何情况下,仍然使用访问的原实。

+0

为什么downvote?我已经说过它很丑陋,但迄今为止它也是唯一的工作解决方案...... – Jorn

+1

一些堆垛机对于回答自己的问题非常挑剔。我认为这是一个很好的自我回答,但有人可能会采取例外。 –

+0

嗯,这不是我,即使我相信我找到了一个更好的[替代](http://stackoverflow.com/a/36918290/2788872),这会产生干净的代码。 –

2

this作用域问题可以用一个非常简单的class装饰加以解决,并且您不再需要使用难看*箭头功能语法的方法 - 或想以后再范围的问题:

function BindMethods(target: any): any { 
    var originalCtor = target; 
    var newCtor: any = function (...args) { 
     var c: any = function() { 
      // Methods are defined on prototype. 
      var prototype = Object.getPrototypeOf(this); 

      // Bind methods. 
      Object.keys(prototype).forEach(propertyKey => { 
       if (typeof this[propertyKey] === "function") { 
        prototype[propertyKey] = this[propertyKey].bind(this); 
       } 
      }); 

      // Invoke original constructor. 
      return originalCtor.apply(this, args); 
     } 
     c.prototype = originalCtor.prototype; 
     return new c(); 
    } 

    // Copy prototype so 'intanceof' still works. 
    newCtor.prototype = originalCtor.prototype; 

    // Overrides original constructor. 
    return newCtor; 
} 

使用它是作为捕捉它的一类一样简单(methodExample方法被修改仅用于演示目的):

@BindMethods 
class Base { 
    value: string; 

    methodExample() { 
     console.log(this.value); 
    } 
} 

这将确保到this参考我总是正确的(即使有继承):

var base = new Base(); 
base.value = "two"; 
base.methodExample(); // "two" 
setTimeout(base.methodExample, 20); // "two" 

不幸的是,没有办法以结合方法中的一个接一个的使用方法装饰,因为需要一个实例参考。如果这是一项要求,您可以使用decorator factory传递方法的属性键进行绑定。使用方法时


*难看。