Pierre
Pierre

Reputation: 6172

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!

Upvotes: 2

Views: 1183

Answers (1)

Felix Kling
Felix Kling

Reputation: 816522

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).

Upvotes: 5

Related Questions