Pierre Pierre - 23 days ago 8
Javascript Question

How to clone an ES6 class object constructor?

Making a simple ORM with ES6 classes, I run with a blocking issues – I can't properly copy a class (as I would have with

util.extend
in ES5).

Specifically, here is what I tried:

class BaseModel {

echo() {
console.log(this.props);
}

static _setProperties(props) {
this.props = props;
}

}

function makeModel(props) {

// Try to copy the Class object
const Model =
Object.assign(Object.create(Object.getPrototypeOf(BaseModel)), BaseModel);

// Copy my static methods – is there a better way to do this?
Object.getOwnPropertyNames(BaseModel).forEach((key) => {
if (!key.startsWith('_')) return;
Model[key] = BaseModel[key];
});

// Configure the new model
Model._setProperties(props);
return Model;
}

const GreeterModel = makeModel('hello');
const greeter = new GreeterModel();
greeter.echo(); // Should log hello


The error I get is:

TypeError: GreeterModel is not a constructor


Is there any way to achieve this with ES6 classes, or do I have to stick to ES5-style?

Optional question: is there a better way to copy the static methods? The solution with
getOwnPropertyNames
is not ideal as it returns also read-only properties, such as
length
.

Thanks!

Answer Source

There is a logic mistake in your base class. this always depends on how a function is called. A static function is usually called on the constructor, i.e. BaseModel._setProperties(...) in which case this refers to BaseModel. Instance methods however are called on an the instance itself, therefore this refers to the instance not the constructor.

To make BaseModel work you would have to use

echo() {
  console.lof(this.constructor.props);
}

But to answer your actual question, you can simply extend the class:

function makeModel(props) {
  class Model extends BaseModel {}
  Model._setProperties(props);
  return Model;
}

Note that this is isn't "cloning" the base class, it's extending it. There is no reasonable way to clone a function in JavaScript (not so far fat least).