class A{
constructor(input: string) {
// do stuff
}
f() {console.log("A")}
}
class B extends A{
constructor(input: string) {
// do stuff
}
f() {console.log("B")}
}
class C extends A{
constructor(input: string) {
// do stuff
}
f() {console.log("C")}
}
Run Code Online (Sandbox Code Playgroud)
我目前有以下设置。这可能听起来很奇怪,但我想new A(inp)根据输入调用返回 B 或 C 的实例(即使它是as A根据 TypeScript 返回的),以便调用(new A("B")).f()将打印“B”,与传递“C”相同,而默认为“A”。这是否可能以一种不严重违反任何规定的方式实现?目前我在 A 中使用静态方法来实现此目的,但我认为使用构造函数会更简洁。
如果类 constructor 方法显式地return指定 以外的对象this,那么当您在类构造函数上使用运算new符this时,您将获得该对象,而不是创建的新对象(在构造函数方法体内调用)。
class Foo {
fooProp: string;
constructor() {
this.fooProp = "abc" // initialize fooProp on the new object
return {
fooProp: "zyx", // but return something completely different
}
};
}
const f = new Foo();
console.log(f.fooProp) // zyx, not abc
Run Code Online (Sandbox Code Playgroud)
这并不常见,并且会产生一些令人惊讶的后果,例如从new构造函数中获得的值不一定是instanceof该构造函数:
console.log(new Foo() instanceof Foo) // false !
Run Code Online (Sandbox Code Playgroud)
人们往往会避免这样做,除非有令人信服的理由。(由您决定您的理由是否足够令人信服)。
只要返回的对象是可分配给类类型的类型,TypeScript 就允许您return使用方法。 constructor 在您的情况下,这很好,因为您显式返回子类。所以从表面上看,是的,这是可能的。
这是一种方法:
class A {
constructor(input?: string) {
if (input === "B") return new B();
if (input === "C") return new C();
}
f() { console.log("A") }
}
class B extends A {
constructor() {
super()
}
f() { console.log("B") }
}
class C extends A {
// still has implicit constructor that calls super
f() { console.log("C") }
}
const a = new A().f(); // A
const b = new A("B").f(); // B
const c = new A("C").f(); // C
Run Code Online (Sandbox Code Playgroud)
我将A的构造函数参数设为可选,并且B不C采用任何构造函数参数。如果您使用A确切的字符串调用构造函数"B"或"C"获得子类实例,否则您将获得 的直接实例A。由于B和C实例也是,那么你就不会得到上面提到的instanceof A奇怪行为。new A("B") instanceof A === false我们来测试一下:
const a = new A();
a.f(); // A
const b = new A("B");
b.f(); // B
const c = new A("C");
c.f(); // C
console.log(a instanceof A); // true
console.log(b instanceof A); // true
console.log(c instanceof A); // true
Run Code Online (Sandbox Code Playgroud)
所以这正是你想要的。
但这对我来说有点令人担忧,因为A的构造函数有两个完全不同的角色,如果你将它们混合在一起,那么可能会发生不好的事情。子类构造函数B和必须显式(如 中)或隐式(如 中)C调用该super()方法,因此您最终会得到等效于call 的结果,而您实际上只想要 的直接实例。同时,外部调用者有时需要一个或一个. 如果您不小心混淆了这些角色并执行以下操作:BCnew A()ABC
class B extends A {
constructor() {
super("B") // TOO MUCH RECURSION
}
}
Run Code Online (Sandbox Code Playgroud)
然后你会得到无限回归和运行时错误。
但这就是所问问题的答案。
您可能需要考虑将A's设为 constructor 一个protected方法,然后使用一个static方法来选择要调用的构造函数。例如:
class A {
protected constructor() { }
f() { console.log("A") }
public static make(input?: string) {
if (input === "B") return new B();
if (input === "C") return new C();
return new A();
}
}
class B extends A {
f() { console.log("B") }
}
class C extends A {
f() { console.log("C") }
}
const a = A.make();
a.f(); // A
const b = A.make("B");
b.f(); // B
const c = A.make("C");
c.f(); // C
console.log(a instanceof A); // true
console.log(b instanceof A); // true
console.log(c instanceof A); // true
Run Code Online (Sandbox Code Playgroud)
行为是相似的,尽管外部调用者使用A.make(xxx)而不是new A(xxx),它专门由类实现本身使用。据我所知,这或多或少是你已经在做的事情。它可能不像直接使用构造函数那么“简洁”,但人们更容易理解发生了什么。
| 归档时间: |
|
| 查看次数: |
2587 次 |
| 最近记录: |