How do I clone a JavaScript class instance?

Solution 1:

How do I clone a JavaScript class instance?

It's hardly possible if the instance was created with heavy use of closures in the constructor function. We may never now which internal values were set, and how to reproduce such a setup. Therefore, the easiest way would be if every class offered a clone function which knows what to do.

normal jQuery extend just returns a vanilla object

Not necessarily, it returns what you passed in. Use

var clone = $.extend(true, Object.create(Object.getPrototypeOf(child)), child);

instead and your instanceof usage will work fine. Note that the true signifies a "deep" copy which may or may not be what you want. Also, $.extend will happily copy enumerable inherited properties as well, so you might need to use a more sophisticated extend function.

Or without jQuery at all, and only copying own, enumerable properties and only using a shallow copy:

var clone = Object.assign(Object.create(Object.getPrototypeOf(child)), child);

But again, not all objects will be clonable in this way, see my first point above.

Solution 2:

This will create a copy of an object with the same prototype (class) and same own properties (including enumerability/writability/getters/setters etc):

function clone(obj) {
  return Object.create(
    Object.getPrototypeOf(obj), 
    Object.getOwnPropertyDescriptors(obj) 
  );
}

(see here)

It doesn't necessarily work well for builtin objects. For example Array.isArray(clone([])) is false, and clone(function () {})() says it is not a function, but for user created objects (either class instances or object literals) it works fine.

To do a deep clone, you will have to loop over the property descriptors and clone the values recursively:

function deepClone(obj) {
  if (obj === null || typeof obj !== "object")
    return obj
  var props = Object.getOwnPropertyDescriptors(obj)
  for (var prop in props) {
    props[prop].value = deepClone(props[prop].value)
  }
  return Object.create(
    Object.getPrototypeOf(obj), 
    props
  )
}