我可以在 JavaScript 中动态地将一个类的实例转换为另一个类的实例吗?

yeo*_*uuu 4 javascript ecmascript-6

python 已经回答了这个问题:我可以动态地将一个类的实例转换为另一个类的实例吗?

但我很好奇这在 ES6/ES2015 的 Javascript 中是否可行。

class A { ... }
class B extends A { ... }
class C extends A { ... }

let test = new B();

// ... After a while I want to have an instance of C instead of B in test.
Run Code Online (Sandbox Code Playgroud)

这可能吗?或者这是一个坏主意?

ssu*_*ube 5

您必须为此编写一个方法替换原型(这可以被认为是一个非常糟糕的想法)。B但是,您可以在很大程度上通过直接C控制this和调用方法来对待 的实例。

由于 JavaScript 是鸭子类型并且没有强类型,因此传统的转换(通常是类型转换)几乎没有意义。所有状态和行为都附加到实例及其原型(甚至在运行时),而不是编译器对类型的理解。

C您可以使用以下方法调用任何方法test

C.prototype.methodName.call(test, arg1, arg2);
Run Code Online (Sandbox Code Playgroud)

call函数上的方法使用指定的 调用该函数this,因此您可以在完全不相关的对象上调用方法(只要它们共享契约,它就会起作用)。

您始终可以声明一个复制构造函数以转换BC,使用:

class C extends A {
  static fromB(other: B): C {
    return new C(B.foo, B.bar);
  }
}
Run Code Online (Sandbox Code Playgroud)

(为了清楚起见,使用 Flow/Typescript 类型注释)

最后,也是我最不喜欢的,是通过破坏原型来声称这test实际上是事后的一个实例:C

Object.setPrototypeOf(test, C);
Run Code Online (Sandbox Code Playgroud)

setPrototypeOftest将用对的引用替换对的B引用C,并且 on 上的任何方法都C.prototype可以通过 访问test,就像上面的显式C.prototype调用一样,但不需要指定 athis和 using .call

您也可以选择简单的选项,将任何共享方法移至此处A,从而完全避免此问题,但这些是 JS 中的强制转换等价物。