2016-04-28 68 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傳遞方法的屬性鍵進行綁定。使用方法時


*難看。