1

How does one clone an existing class (not the instance of a class)?

class Base {
  constructor(input='base') {
    this.base = input
  }
}

class CloneBase {
  constructor(input='CloneBase') {
    this.base = input
  }
}

class A extends Base {
  get a() {
    return "a"
  }
}

const Clone = A // how does one clone A?

Object.setPrototypeOf( Clone, CloneBase )

const a = new A()
console.log(a.base) // should be "Base"

const clone = new Clone()
console.log(Clone.base) // should be "CloneBase"

I could use an instance of the class, but that bypasses the constructor in subsequent code and can't be used with new Clone(whatever)

TrevTheDev
  • 2,616
  • 2
  • 18
  • 36

2 Answers2

1

You cannot clone a class in javascript. Lets take a look at this example:

function classCloner(x) {
  var constructor = function() {
    if(!(this instanceof constructor)) throw new TypeError("Not a constructor");
    x.apply(this, Array.prototype.slice.call(arguments));
  }
  for(var attr in x) {console.log(attr);
    if(Object.hasOwnProperty(attr)) constructor[attr] = x[attr];
  }
  constructor.prototype = Object.create(Object.getPrototypeOf(x.prototype));
  for(var attr in x.prototype) {
    if(Object.hasOwnProperty(attr)) constructor.prototype[attr] = x.prototype[attr];
  }
  return constructor;
}

This function doesn't work:

  1. ECMA6 classes uses checks in the constructor and member functions, so that you cannot directly invoke the class without new. It checks if this instanceOf constructor
  2. If you clone a class, you need to clone all properties. Many properties are functions and they only work with one type, creating multiple types could cause weird errors.

Still there is a way to clone an ECMA6 class, using eval.

var clonedClz = eval(oldClz.toString());

This will clone all properties of the class, and will clone all functions. When oldClz is modified after it was created (e.g oldClz.foo = () => 'bar'), then that change will not apply to the cloned class.

This works, only for ecmascript6 classes, and not for plain js classes. Creating multiple types with the same functions can cause big issues.

SmileDeveloper
  • 366
  • 3
  • 10
  • Thanks that is the solution: const clsString = `(${A.toString().replace("A extends Base", "Clone extends CloneBase")})` const Clone = eval(clsString) – TrevTheDev Jul 10 '20 at 07:01
0

Object.assign

let clone = Object.assign( Object.create( Object.getPrototypeOf(orig)), orig)

Please visit this link to more info.

Krishan Kumar
  • 394
  • 4
  • 13
  • 2
    OP asked for the class, not the instance. – Bren Jul 10 '20 at 03:35
  • This solution bypasses the class constructor, which I want to execute as per usual. Also, it creates a new object at instantiation which I believe will not be as performant as having a predefined class instantiated via new [but I may be wrong]. But thanks for the answer. – TrevTheDev Jul 10 '20 at 05:33
  • welcome @TrevTheDev , glad to know that you could resolved it. – Krishan Kumar Jul 10 '20 at 06:09
  • 1
    @kk4You no the problem is not solved, as there seems to be no way to duplicate a class – TrevTheDev Jul 10 '20 at 06:18