假设以下 Typescript 示例
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
是预期的。
我们如何从父 constructor()
中用子属性做事?
实际想法:
- super() 调用 child construct() 解决了问题,但我需要对每个 child 都这样做。不是很优雅的解决方案。
- 在父构造上使用超时记录正确的值,但不可能立即使用类的实例(因为超时尚未执行)。
最佳答案
我非常喜欢 Jeff 和 Duncan 已经提出的建议。不过,让我再展示一个选项。
abstract class Animal {
constructor(public name: string) {
console.log(this.name);
}
}
class Snake extends Animal { }
let someSnake = new Snake("Snakeeeey!");
请注意这里的一些事情。
Animal
类似乎确实是一个抽象概念。您可以选择将其标记为abstract
或将其定义为interface
,但后者不会让您有任何实现(包括构造函数)。- TypeScript 允许我们定义从构造函数初始化的字段。对于公共(public)属性,我们只需编写
constructor(public name: string)
。 Snake
类没有显式定义构造函数。然而,在创建蛇对象时,消费者必须提供Animal
类 所需的name
参数。在 Jeff 的代码中,Snake 类有一个
name
的默认值,这是通过constructor(name: string = 'BeatSSS') { super(name); 实现的。 }
。我不知道你的具体用例。如果蛇没有任何有意义的默认名称,我会完全避免声明此类构造函数。Duncan 正确地解释了调用
super()
本身并不是错误的。而且,这是必要的。当
Snake
类型的对象通过其构造函数创建时,父(Animal
)的构造函数必须首先完成。因此,Animal
构造函数无法“看到”发生在子(Snake
)构造函数中的字段初始化效果。由于构造函数调用的顺序,这是不可能的。因此,子类型传递父类构造函数信息的唯一选择是直接调用
super(...)
。
super()
call on childconstruct()
solve the problem, but I need do it on every child. Not very elegant solution.
基本上完全不定义子构造函数就是答案。如果您的子类必须拥有构造函数,他们将强制您调用super()
作为the very first instruction .
using a timeout on parent construct logs the correct value, but is not possible use the instance of class immediately (beacouse timeout is not executed yet).
这是一个非常糟糕的选择。首先,通常不建议在构造函数中调用任何异步代码。
其次,如果您仍然在 Animal
构造函数中执行 setTimeout(() => this.fixMyState(), 0)
会导致不好的效果:紧接着对象构造,对象处于错误状态。如果某些代码立即使用该对象怎么办? () => this.fixMyState(), 0
甚至没有机会运行以修复对象。根据经验,对象在构建后立即处于良好状态 是一种经验法则。否则,构造函数应该抛出
一个错误,这样就没有代码可以尝试对处于错误状态的对象进行操作。
关于typescript - 从父构造函数访问子属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46866467/