4

The question is already answered for python: Can I dynamically convert an instance of one class to another?

But I was curious if this would be possible in Javascript with ES6/ ES2015.

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.

Is this possible? Or is it a bad idea?

Community
  • 1
  • 1
yeouuu
  • 1,863
  • 3
  • 15
  • 32
  • 2
    Can you show a usage case? JavaScript doesn't have actual classes, they are just syntactic sugar that allow for easier prototypical inheritance. You will have to show what you mean by "convert" to another instance. – 4castle Jul 05 '16 at 14:57

1 Answers1

5

You would have to write a method for this or replace the prototype (which can be considered a Very Bad Idea). However, you can largely treat an instance of B as if it were C by controlling this and calling the methods directly.

Since JavaScript is duck-typed and has no strong types, the traditional conversion (type casting, usually) is mostly meaningless. All state and behavior is attached to the instance and its prototype (even during runtime) rather than the compiler's understanding of the type.

You can call any of the methods from C on test using:

C.prototype.methodName.call(test, arg1, arg2);

The call method on a function invokes the function with a specified this, so you can call a method on a totally unrelated object (and it will work, so long as they share a contract).

You can always declare a copy constructor to turn B into C, using:

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

(using Flow/Typescript type annotations for clarity)

Finally, and my least favorite, is claiming that test is actually an instance of C after the fact by mucking with the prototype:

Object.setPrototypeOf(test, C);

setPrototypeOf will replace test's reference to B with a reference to C and any methods on C.prototype will be accessible via test, like the explicit C.prototype call above but without needing to specify a this and using .call.

You could also go for the simple option of moving any shared methods to A and avoid this problem altogether, probably, but these are the JS equivalents of a cast.

ssube
  • 47,010
  • 7
  • 103
  • 140