简体   繁体   English

为什么Typescript首先运行抽象类?

[英]Why does Typescript run the abstract class first?

I'm getting a hard time trying to solve my abstract class issue with Typescript. 我很难用Typescript解决我的抽象类问题。 First of all, let me know what I'm trying to achieve. 首先,让我知道我想要的目的。

I have a class called Sword which extends Weapon . 我有一个名为Sword的类,它扩展了Weapon Each Weapon has to have some properties such as damage , but since each item has a different damage type (eg Sword may do 1 damage, a bow may do 2 damage) I have to define specific properties in the Sword class. 每个Weapon都必须具有某些属性,例如damage ,但是由于每个物品都有不同的伤害类型(例如,剑可能造成1点伤害,弓箭可能造成2点伤害),我必须在Sword类中定义特定的属性。 My script looks like this: 我的脚本如下所示:

abstract class Weapon
{
    protected abstract damage: number;
    constructor() {
        alert(this.damage);
    }

    showDamage() {
        alert(this.damage);
    }
}

class Sword extends Weapon implements WeaponInterface {
    protected damage: number = 999;

    constructor() {
        super();
    }
}

const sword = new Sword;
sword.showDamage();

Running the script above at http://www.typescriptlang.org/play/ , I get two messages: http://www.typescriptlang.org/play/运行上述脚本,我收到两条消息:

undefined
999

I'm not exactly sure why Weapon.constructor runs first, because as long as Weapon.constructor runs first, there is literally no point in declaring an abstract value. 我不确定为什么Weapon.constructor运行Weapon.constructor ,因为只要Weapon.constructor运行Weapon.constructor ,就没有必要声明抽象值。 For example, I have to do something like super(this.damage) in order to pass it into Weapon class. 例如,我必须做类似super(this.damage)的操作才能将其传递到Weapon类中。 I won't need the protected abstract damage if I do so. 如果需要,我将不需要protected abstract damage

If I cannot even create a very basic inheritence with Typescript , why does it even support abstract classes at all? 如果我什至无法使用Typescript创建非常基本的继承,为什么它甚至完全支持抽象类? I'll have to do new Weapon(new Sword) which means I cannot typehint SwordInterface on other classes like Inventory . 我必须做new Weapon(new Sword)这意味着我不能typehint SwordInterface其他类,如Inventory

class Inventory
{
    // Let's assume we have a "Shield" equipped so we can only equip "Sword" type
    addSword(sword: SwordInterface): void {

    }
}

I'm not very experienced with compiled languages and Typescript. 我对编译语言和Typescript不太有经验。 Could anybody tell me what would be the proper way to achieve this? 有谁告诉我,这将是实现这一目标的正确方法? Passing class properties into super() call sounds lame... 将类属性传递给super()调用听起来很me脚...

I don't want to break my inheritence and interfaces either. 我不想打破我的传承与接口两种。

Typescript does not treat property initialization in the class body in any special way - it's done as part of that class constructor. Typescript不会以任何特殊方式处理类主体中的属性初始化-它是该类构造函数的一部分。 It's possible to imagine a language that will apply this assignment 可以想象一种语言将应用此分配

class Sword extends Weapon implements WeaponInterface {
    protected damage: number = 999;

very early, before any constructor is run. 很早,在运行任何构造函数之前。 Typescript does not do that probably because it's not the simplest and most consistent thing to do. Typescript不会这样做,可能是因为这不是最简单,最一致的事情。

So you have to do it yourself. 所以你必须自己做。 One way to achieve what you want is to split code in your constructors into two parts, one that initializes the variables, and the other one that does the rest. 一种实现所需目标的方法是将构造函数中的代码分成两部分,一个部分初始化变量,另一部分完成其余部分。 Then you can manage yourself when each part is called. 然后,当每个部分被调用时,您就可以管理自己。 This technique is sometimes called two-phase initialization : 该技术有时称为两阶段初始化

abstract class Weapon
{
    protected abstract damage: number;

    // NOTE: abstract properties must be initialized by subclasses
    //     in initialize() because they are used here in Weapon class constructor
    protected initialize(): void { }

    constructor() {
        this.initialize();
        alert(this.damage);
    }

    showDamage() {
        alert(this.damage);
    }
}

class Sword extends Weapon  {
    protected damage: number;

    protected initialize(): void {
        super.initialize();
        this.damage = 999;
    }

    constructor() {
        super();
    }
}

const sword = new Sword;
sword.showDamage(); // shows 999 twice

Of course base class constructors run first. 当然,基类构造函数首先运行。 What would the alternative be? 替代方案是什么?

class Base {
  damage = 12;
}

class Derived extends Base {
  constructor() {
    // This should print 'undefined' ?
    console.log(this.damage);
  }
}

The base c'tor is run before the assignment of damage . 基本角色在分配damage之前运行。 Take a look at the generated constructor of Sword : 看一下生成的Sword构造函数:

function Sword() {
    var _this = _super.call(this) || this;
    _this.damage = 999;
    return _this;
}

As an alternative you could pass the damage as base c'tor parameter: 或者,您可以将损伤作为基本参数传递:

abstract class Weapon {

    protected damage: number;

    constructor(damage: number) {
        this.damage = damage;
        alert(this.damage);
    }

    showDamage() { /*...*/ }
}

class Sword extends Weapon  {

    constructor() {
        super(999);
    }
}

Or shorter: 或更短:

abstract class Weapon {
    constructor(protected damage: number) {
        alert(this.damage);
    }

    showDamage() { /* ... */ }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM