2017-10-21 63 views
1

假定以下打字稿示例打字稿:获得子属性从父构造

class Animal { 
    public name: string; 

    constructor() { 
     console.log(this.name); 
    } 
} 

class Snake extends Animal { 
    public name = 'BeatSSS'; 
} 

let someSnake = new Snake(); 

当然,的console.log日志undefined。预计BeatSSS

我们怎样才能从父构造()与儿童属性做的事情?

实际的想法:儿童结构

  • 超()()调用解决这个问题,但我需要做的每一个孩子。不是很优雅的解决方案
  • 在父构造上使用超时记录正确的值,但不可能立即使用类的实例(尚未执行beacouse超时)。
+2

当调用父构造函数时,对象尚未完全形成。它只是父母的一部分。这就是几乎所有的OOP语言的工作原理。 – 2017-10-21 18:53:36

回答

1

我喜欢杰夫和邓肯已经提出的很多。不过,让我再展示一个选项。

abstract class Animal { 
    constructor(public name: string) { 
     console.log(this.name); 
    } 
} 

class Snake extends Animal { } 

let someSnake = new Snake("Snakeeeey!"); 

注意这里的几件事情。

  • Animal类似乎确实是一个抽象的概念。您可以选择将其标记为abstract或将其定义为interface,但后者不会让您有任何实现(包括构造函数)。
  • TypeScript允许我们定义从构造函数初始化的字段。在公共财产的情况下,我们只需编写constructor(public name: string)
  • Snake类不明确明确定义了一个构造函数。然而,在创建蛇物品时,消费者必须提供Animal类别所要求的name参数。

    在Jeff的代码中,Snake类的name的默认值是constructor(name: string = 'BeatSSS') { super(name); }。我不知道你的具体用例。如果没有任何有意义的默认名称为蛇,我会避免完全声明这样的构造函数。

  • 邓肯正确地解释说,调用super()并非天生就是错误的。而且,这是必要的。

    当通过构造函数创建Snake类型的对象时,必须首先完成父(Animal)的构造函数。因此,Animal构造函数无法“查看”子项(Snake)构造函数中发生的字段初始化的影响。由于构造函数调用的顺序,这是不可能的。

    因此,子类型为父类构造函数传递信息的唯一选项是直接调用super(...)。儿童construct()


super()呼叫解决这个问题,但我需要做的每一个孩子。不是很优雅的解决方案

基本上没有完全定义子构造函数就是答案。如果您的孩子类必须具有构造函数,他们将强制您调用super()作为the very first instruction

在父构造上使用超时记录正确的值,但不能立即使用类的实例(beacouse超时尚未执行)。

这是一个非常糟糕的选择。首先,一般不建议在构造函数中有任何异步代码调用。

其次,如果你还做了在AnimalsetTimeout(() => this.fixMyState(), 0)构造它会导致不良的影响:对象构造后立即对象是在糟糕的状态。如果某些代码立即使用该对象会怎么样? () => this.fixMyState(), 0甚至没有机会运行修复对象。建立后立即在良好状态中有一个对象是一条经验法则。否则,构造函数应该会出现错误throw,这样就没有代码可以尝试对处于不良状态的对象进行操作。

1

如果你对每个孩子都需要这个,你应该把name参数传递给父类的构造函数。

1

什么是不是优雅的打电话给超级?你用其他语言做它,在打字稿中做什么错?

您正在设置一个属性,该类对于正确运行的类是固有的。通过构造函数设置这些属性。

abstract class Animal { 
    constructor(public name: string) { 
    } 
} 

class Snake extends Animal { 
    constructor(name: string = 'BeatSSS') { 
     super(name); 
    } 
} 

let someSnake = new Snake();   // use the default name 'BeatSSS' 
let anotherSnake = new Snake('Foo'); // use a different name 

class Dog extends Animal { 
    constructor(name: string = 'Rover') { 
     super(name); 
    } 
} 

let someDog = new Dog(); 
let anotherDog = new Dog('Bar');