0

Looking through the meteor TODOs app I noticed a particular class pattern.

class ListsCollection extends Mongo.Collection {
  //Other methods, no constructor
}
export const Lists = new ListsCollection('lists');

This code uses new, though there is no ListsCollection constructor. My interpretation, is that the constructor of Mongo.Collection is being called by prototype delegation.

Throughout the rest of my code, I am using Kyle Simpson's OLOO Pattern and i would like to use the same pattern here.

const ListsCollection = {
  init() {
    //Call the constructor of Mongo.Collection
    return this;
  },
  //Same methods
}
Object.setPrototypeOf(ListsCollection, Mongo.Collection);
export const Lists = Object.create(ListsCollection).init('lists');

I've started, however I am not sure how to call the constructor of the Mongo.Collection class. Any suggestions would be appreciated :D.

EDIT - following answers

I have replaced the comment in my second code snippet with Mongo.Collection.call(this), which should have the desired effect. However, i get the error Error: use "new" to construct a Mongo.Collection. I'm not sure the best way to work around this.

EDIT 2 - following investigation

The offending line found in the Mongo.Collection constructor function, causing the error is:

if (! (self instanceof Mongo.Collection))
  throw new Error('use "new" to construct a Mongo.Collection');

since instanceof tests for existence of Mongo.Collection.prototype up the prototype chain, it is clearly not present.

This was solved by changing

Object.setPrototypeOf(ListsCollection, Mongo.Collection);

To

Object.setPrototypeOf(ListsCollection, Mongo.Collection.prototype);
Seb Morris
  • 380
  • 1
  • 8
  • 1
    Why not stick with classes? – Felix Kling Aug 03 '17 at 18:52
  • I usually would, I'm simply taking this pattern to completion to see how i feel about it at the end of a project. The advantages are described here: [relevant YDKJS chapter](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch6.md) – Seb Morris Aug 03 '17 at 18:56
  • Is there something wrong with your first example? It looks better to me, if Mongo.Collection.call is not working for you. – lilezek Aug 03 '17 at 19:26
  • Mentioned in the comment above. I should be able to do it both ways. – Seb Morris Aug 03 '17 at 19:27

1 Answers1

1

I think you want to do:

Mongo.Collection.call(this);

at the place you have your comment.

Remember that a class in JavaScript, either older versions and new ES6 version, is a function representing its own constructor.

Seb Morris
  • 380
  • 1
  • 8
lilezek
  • 6,976
  • 1
  • 27
  • 45
  • Of course, it seems so obvious now... I was thinking something similar, e.g. `(new Mongo.Collection).bind(this)` however I was aware you cannot combine `bind` and `new`. Thanks for the answer, ill try it out – Seb Morris Aug 03 '17 at 18:54
  • Unfortunately, using `Mongo.Collection.call(this)` I get the error: `Error: use "new" to construct a Mongo.Collection` – Seb Morris Aug 03 '17 at 19:17
  • Solution in question edits. Since my edit to this answer has been accepted, i am marking it as the answer. – Seb Morris Aug 03 '17 at 19:34
  • Well, check this also https://stackoverflow.com/questions/10428603/simulate-the-new-operator-in-javascript , you could try to simulate `new` operator aswel. – lilezek Aug 03 '17 at 19:35
  • 1
    Keep in mind that the error explicitly says `use "new" to construct`, which this isn't doing. It'd totally valid for them to introduce something that would break when used with `.call` in the future without a semver major version bump. – loganfsmyth Aug 03 '17 at 21:41