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

时间:2017-01-11 19:51:27

标签: inheritance typescript

我正在努力用Typescript解决我的抽象类问题。首先,让我知道我想要实现的目标。

我有一个名为Sword的类,它扩展了Weapon。每个Weapon必须具有一些属性,例如damage,但由于每个项目都有不同的伤害类型(例如,剑可能造成1点伤害,弓箭可能造成2点伤害)我必须在Sword课程。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(); 。我的脚本看起来像这样:

http://www.typescriptlang.org/play/

undefined 999 运行上面的脚本,我收到两条消息:

Weapon.constructor

我不确定为什么Weapon.constructor首先运行,因为只要super(this.damage)先运行,就没有必要声明一个抽象值。例如,我必须执行Weapon之类的操作才能将其传递到protected abstract damage类。如果我这样做,我将不需要Typescript

如果我甚至无法用new Weapon(new Sword)创建一个非常基本的继承,为什么它甚至支持抽象类呢?我必须SwordInterface这意味着我无法在Inventory等其他类上输入提示class Inventory { // Let's assume we have a "Shield" equipped so we can only equip "Sword" type addSword(sword: SwordInterface): void { } }

super()

我对编译语言和Typescript不是很熟悉。谁能告诉我实现这个目标的正确方法是什么?将类属性传递给@echo off setlocal EnableDelayedExpansion set "order=RSSI RSRP RSRQ SINR "Tx Power" PCI" rem Extract the "order" string into individual numerated elements set "i=0" for %%a in (%order%) do ( set /A i+=1 set "order[%%~a]=!i!" ) rem Process the files and create an array with the desired order set "lastFloor=0" for /F "tokens=1-5 delims=_" %%a in ('dir /A:-D /B *.jpg') do ( set "name[%%b][!order[%%d]!]=%%a_%%b_%%c_%%d_%%e" if %%b gtr !lastFloor! set "lastFloor=%%b" ) rem Process the array elements for /L %%i in (1,1,%lastFloor%) do ( for /F "tokens=2 delims==" %%a in ('set name[%%i]') do echo %%a ) 调用声音蹩脚......

我也不想破坏我的继承和接口。

3 个答案:

答案 0 :(得分:3)

Typescript不会以任何特殊的方式处理类体中的属性初始化 - 它是作为该类构造函数的一部分完成的。可以想象一种将应用此作业的语言

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

很早,在任何构造函数运行之前。打字稿不这样做可能是因为它不是最简单和最一致的事情。

所以你必须自己做。实现所需的一种方法是将构造函数中的代码分成两部分,一部分用于初始化变量,另一部分用于完成其余部分。然后,您可以在调用每个部件时自行管理。这种技术有时称为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

答案 1 :(得分:1)

当然,基类构造函数首先运行。替代方案是什么?

class Base {
  damage = 12;
}

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

答案 2 :(得分:1)

基础c'tor在分配damage之前运行。看一下Sword生成的构造函数:

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

作为替代方案,你可以将伤害作为基础c'tor参数传递:

abstract class Weapon {

    protected damage: number;

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

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

class Sword extends Weapon  {

    constructor() {
        super(999);
    }
}

或更短:

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

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