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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 03:26:59  来源:igfitidea点击:

Typescript overridden class method and this

typescript

提问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 thisreferences 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 someMethodfrom (for example) a click handler - someEl.onclick = instanceOfMyClass.someMethod;- an exception would be raised (assuming windowdoesn'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 someMethodas a property of someInstanceOfMyClassand not passing it into an event handler (which turns it into a property of window) you ensure that thisis always an instance of MyClass.

它有点冗长和迂腐,但通过someMethod作为 of 的属性调用someInstanceOfMyClass而不是将其传递给事件处理程序(将其转换为 的属性window),您可以确保this始终是 的实例MyClass

回答by John Weisz

The scoping issue of thiscan 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 (methodExamplemethod was modified for demonstration purposes only):

使用它就像在类上捕捉它一样简单(methodExample修改方法仅用于演示目的):

@BindMethods
class Base {
    value: string;

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

This will ensure the reference to thisis 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 Baseis methodExample.

例如,这一行定义了一个property,而不是一个 on 的方法Base,并且您不能覆盖一个 property。您在其中定义的唯一实例方法BasemethodExample.

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. methodExamplein your Childclass shows up as a syntax error for me.

在 中Child,您正在为 分配一个新变量lambaExample。您的调用super.lambaExample()失败,因为它只能通过;访问方法super()。访问属性是通过this. methodExample在你的Child课上对我来说显示为语法错误。

Note that you can still call super from Childin the overwritten lambaExampleproperty, 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, thisworks 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 someFunctionon any instance, and still access the original implementation using otherFunction.

这样,您可以调用someFunction任何实例,并且仍然可以使用otherFunction.