Typescript重写了类方法和这个

时间:2016-04-28 14:05:55

标签: typescript

我有这两个Typescript类:

project.pbxproj

如何以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 } } 引用可靠,的方式编写方法我可以覆盖方法并从父类调用它们?

4 个答案:

答案 0 :(得分:2)

实际上很好地了解了Microsoft's Git Wiki解决这个问题的不同方法。它基本上归结为:

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

在实际的Wiki中有更多的规定,我真的建议你阅读整篇文章。

修改

包装的一个例子:

鉴于课程

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

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

}

如果您从(例如)点击处理程序someMethod调用someEl.onclick = instanceOfMyClass.someMethod;,则会引发异常(假设window没有属性{ {1}} 的)。

你可以通过将函数绑定到someProp(不是类型安全,而不是ES6兼容)或通过手动包装它来实现这一点(无论如何,有效地绑定了什么):

instanceOfMyClass

它有点冗长和迂腐,但通过调用someEl.onclick = function() { someInstanceOfMyClass.someMethod(); }; 作为someMethod的属性而不将其传递给事件处理程序(将其转换为someInstanceOfMyClass的属性)确保window始终是this的实例。

答案 1 :(得分: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传递要绑定的方法的属性键。

用于方法的

*丑陋

答案 2 :(得分:1)

您对错误原因的假设是错误的,我认为这是您问题的原因......至少我理解这一点。

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

例如,此行定义了一个属性,而不是Base上的方法,并且您无法覆盖属性。您在Base中定义的唯一方法是methodExample

Child中,您要为lambaExample分配一个新变量。您对super.lambaExample()的来电失败,因为只能通过super()访问方法;访问属性是通过this完成的。 methodExample课程中的Child对我来说是一个语法错误。

请注意,您仍然可以在覆盖的Child属性中从lambaExample调用super,但仅限于方法。这有效:

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';
  }
}

答案 3 :(得分:1)

我找到了一个解决方法,但它很难看:

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

这样,您就可以在任何实例上调用someFunction,并仍使用otherFunction访问原始实现。