typescript 打字稿重写的类方法和这个
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36917112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Typescript overridden class method and this
提问by Jorn
I have these two Typescript classes:
我有这两个 Typescript 类:
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
}
}
How do I write my methods in such a way that this
references are reliable, andI can override methods and call them from the parent class?
我如何以this
引用可靠的方式编写我的方法,并且我可以覆盖方法并从父类调用它们?
采纳答案by Sandy Gifford
There's actually a good look at the different ways of tackling this problem on Microsoft's Git Wiki. It essentially comes down to this:
实际上,在Microsoft 的 Git Wiki上可以很好地了解解决此问题的不同方法。它基本上归结为:
- Bind or wrap the method every time it's called from a different context if you care about inheritance.
- Turn the method into a property that contains a function if you don't.
- 如果您关心继承,则每次从不同的上下文调用该方法时都绑定或包装该方法。
- 如果不这样做,请将方法转换为包含函数的属性。
There are many more stipulations in the actual Wiki and I really recommend you read the whole thing.
实际的 Wiki 中有更多规定,我真的建议您阅读整篇文章。
EDIT
编辑
An example of wrapping:
包装的一个例子:
Given the class
鉴于班级
class SomeClass {
public someProp: string = "Hello World";
public someMethod() {
console.log(this.someProp);
}
}
If you were to call someMethod
from (for example) a click handler - someEl.onclick = instanceOfMyClass.someMethod;
- an exception would be raised (assuming window
doesn't have a property someProp
).
如果您someMethod
要从(例如)单击处理程序调用someEl.onclick = instanceOfMyClass.someMethod;
- 将引发异常(假设window
没有属性someProp
)。
You can circumvent this by either binding the function to instanceOfMyClass
(not type-safe, not ES6 compatible) or by manually wrapping it (effectively what bind is doing, anyway):
您可以通过将函数绑定到instanceOfMyClass
(非类型安全,与 ES6 不兼容)或手动包装它(实际上绑定正在做什么)来规避此问题:
someEl.onclick = function() {
someInstanceOfMyClass.someMethod();
};
It's a little bit verbose and pedantic, but by calling someMethod
as a property of someInstanceOfMyClass
and not passing it into an event handler (which turns it into a property of window
) you ensure that this
is always an instance of MyClass
.
它有点冗长和迂腐,但通过someMethod
作为 of 的属性调用someInstanceOfMyClass
而不是将其传递给事件处理程序(将其转换为 的属性window
),您可以确保this
始终是 的实例MyClass
。
回答by John Weisz
The scoping issue of this
can be tackled with a very simple classdecorator, and you no longer need to use the ugly* arrow function syntax for methods -- or think about scoping issues ever again:
的范围问题this
可以通过一个非常简单的类装饰器来解决,并且您不再需要对方法使用丑陋的*箭头函数语法——或者再次考虑范围问题:
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;
}
Using it is as simple as snapping it on a class (methodExample
method was modified for demonstration purposes only):
使用它就像在类上捕捉它一样简单(methodExample
修改方法仅用于演示目的):
@BindMethods
class Base {
value: string;
methodExample() {
console.log(this.value);
}
}
This will ensure the reference to this
is always correct (even with inheritance):
这将确保对的引用this
始终正确(即使有继承):
var base = new Base();
base.value = "two";
base.methodExample(); // "two"
setTimeout(base.methodExample, 20); // "two"
Unfortunately, there is no way to bind methods one-by-one using method decorators, as an instance reference is needed. If that's a requirement, you could use a decorator factoryto pass property keys of methods to bind.
不幸的是,无法使用方法装饰器逐一绑定方法,因为需要实例引用。如果这是一个要求,您可以使用装饰器工厂来传递要绑定的方法的属性键。
*ugly when used for methods.
*丑陋用于方法。
回答by Christopher Currens
Your assumptions about the reasons for the errors are wrong, which I think is the cause of your problem...at least as I understand it.
您对错误原因的假设是错误的,我认为这是导致您出现问题的原因……至少在我的理解中是这样。
lambdaExample = () => {
this.value = 'one';
}
This line, for example is defining a property, not a method on Base
, and you can't override a property. The only instance method you've defined in Base
is methodExample
.
例如,这一行定义了一个property,而不是一个 on 的方法Base
,并且您不能覆盖一个 property。您在其中定义的唯一实例方法Base
是methodExample
.
In Child
, you're assigning a new variable to lambaExample
. Your call to super.lambaExample()
fails because that can only access methodsvia super()
; accessing properties is done via this
. methodExample
in your Child
class shows up as a syntax error for me.
在 中Child
,您正在为 分配一个新变量lambaExample
。您的调用super.lambaExample()
失败,因为它只能通过;访问方法super()
。访问属性是通过this
. methodExample
在你的Child
课上对我来说显示为语法错误。
Note that you can still call super from Child
in the overwritten lambaExample
property, but only on methods. This works:
请注意,您仍然可以Child
在被覆盖的lambaExample
属性中调用 super ,但只能在方法上调用。这有效:
lambdaExample = () => {
super.methodExample(); // Success on super.<somemethod>()
this.value = 'three';
}
I'm only aware of one way to declare an instance method in a class, and if you're consistent with that syntax, this
works as you would expect:
我只知道在类中声明实例方法的一种方法,如果您与该语法一致,则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';
}
}
回答by Jorn
I've found a workaround, but it's ugly:
我找到了一个解决方法,但它很难看:
class Base {
someFunction = () => {
this.otherFunction();
}
protected otherFunction = () => {
// actual implementation here
}
}
class Child {
someFunction = () => {
this.otherFunction();
// additional implementation here
}
}
This way, you can call someFunction
on any instance, and still access the original implementation using otherFunction
.
这样,您可以调用someFunction
任何实例,并且仍然可以使用otherFunction
.