2

Possible Duplicate:
What is the reason to use the ‘new’ keyword here?

I am studying Mongoose (what a beautiful piece of software...) and am seeing this:

function Model (doc, fields, skipId) {
  Document.call(this, doc, fields, skipId);
};

/*!
 * Inherits from Document.
 */
Model.prototype.__proto__ = Document.prototype;

Wow, that's the easiest way to set inheritance I've ever seen. I know it cannot be done with browsers, but server side... it looks like a winner:

  • the derived class calls the constructor of the parent class
  • The prototype object of the derived class is set so that proto points to the parent's class prototype.

And that's it!

Is this possibly the cleanest, easiest way to implement inheritance on the server's side? I am asking because I am in love with it, and am wondering if I am missing some limitations/problems...?

Community
  • 1
  • 1
Merc
  • 16,277
  • 18
  • 79
  • 122

2 Answers2

1

Well, some browser's franeworks used to mimic this by having A.prototype = new B(), but this is a bit hacky :) One important gain of both ways is that monkey-patching parent class enabled descendants to use new/changed methods of the parent (which is not the case with A.prototype = $.extend({}, B.prototype) and similar hacks).

As for the described approach, it definitely looks cleaner, so I would vote for "Yes"

user123444555621
  • 148,182
  • 27
  • 114
  • 126
Anton
  • 2,483
  • 2
  • 23
  • 35
  • `A.prototype = new B()` is not hacky. It is the standard way to do inheritance in javascript. All other methods are hacks. – slebetman Nov 09 '12 at 02:32
  • Isn't it a problem we invoke base class' constructor once per inherited member? I understand it might be the only way, but it does not make it okay. – Anton Nov 09 '12 at 02:36
  • `new B()` is only executed once. It then creates an object. We then set that object to be the prototype of function A. Function A will now inherit methods and attributes of a B object if called via the `new` keyword (not B, remember javascript inherits from objects not functions). the B constructor is never called more than once unless you call it yourself more than once. – slebetman Nov 09 '12 at 02:40
  • Exactly, but what is B's constructor contains some logic? Or expects some arguments? Don't forget B is not neccessarily a dumb container of functions. – Anton Nov 09 '12 at 02:43
  • (by inherited member I meant a descendant of B) – Anton Nov 09 '12 at 02:45
  • B's constructor is still only called once. Unless you can show me where in the code it is called more than once. – slebetman Nov 09 '12 at 02:49
  • The hack you're thinking of where B is called more than once is the module pattern: `function A () {this = new B()}`, which is very different from standard inheritance: `function A(){};A.prototype=new B()` – slebetman Nov 09 '12 at 02:50
  • A.prototype = new B(); C.prototype = new B() would invoke it twice. The problem is not about the number of contructor's invocation, but about the circumstances it is invoked under: is it natural your class' constructor gets invoked for no reason? – Anton Nov 09 '12 at 02:52
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/19315/discussion-between-anton-and-slebetman) – Anton Nov 09 '12 at 02:53
  • 1
    @Anton: You're right that it's not a great approach to have to invoke the constructor just to set up inheritance. To get around it you can use `Object.create`. `A.prototype = Object.create(B.prototype);` – I Hate Lazy Nov 09 '12 at 02:53
  • Well, in that case you should do `var Bobj = new B(); A.prototype = Bobj; C.prototype = Bobj`. This is not what we discussed. Nowhere in the discussion was mentioned about another constructor. We were only discussing descentants of B: `A.prototype = new B();C.prototype = new A();` – slebetman Nov 09 '12 at 02:55
  • 1
    +1 user one six eight nine whatever :) – Anton Nov 09 '12 at 02:55
  • @user1689607 `Object.create(B.prototype)` is exactly the same as `new B()`. See documentation: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create. Both creates and returns an object each call. – slebetman Nov 09 '12 at 02:57
  • 2
    @slebetman: Except that with `new B()` you're invoking the constructor. The point Anton is making is that there may be some undesired side-effect to invoking the constructor just to set up the inheritance. The `Bobj` trick wouldn't really work because `A` and `C` will be using the same object, so they'll see each other's extensions. – I Hate Lazy Nov 09 '12 at 02:58
  • 1
    @slebetman Not only can `B`'s constructor have side-effects, but it may even require some argument. For example, `Human = function (dateOfBirth) { if (typeof dateOfBirth == 'undefined') throw 'Missing argument'; ...};`. Now try and inherit from `Human`... – user123444555621 Nov 11 '12 at 11:07
0

As far as I can tell, that can be done in the client as well like:

Model.prototype = new Document();
Model.prototype.constructor = Model;
elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • It take s bit more to really make it like the code in the question: `Model.prototype = Object.create(Document.prototype, {constructor: {value: Model, configurable: true, writeable: true}});` Not quite as clean. – I Hate Lazy Nov 09 '12 at 02:23
  • I use the same. If we forget the second line, the constructor call when we instantiate a Model class is the parent one (Document constructor in this case). I often use this website as reference https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript – EmeraldCoder Nov 09 '12 at 02:23
  • @user1689607 Wow nice one... I am not familiar with Object.create! Using the constructor: ... parameter, do you also cover the line of code `Document.call(this, doc, fields, skipId);` ...? – Merc Nov 09 '12 at 05:28
  • @Merc: No, the `Document` constructor still needs to be called on each instance like you're currently doing. – I Hate Lazy Nov 09 '12 at 06:00
  • @user1689607 what is that constructor:... for? Any practical use? – Merc Nov 09 '12 at 09:58
  • @Merc: You mean the `.constructor` property being placed on the new `Model.prototype`? It just replaces the one that was lost when the original object was overwritten. It has no impact on any behavior of the constructors, but some people rely on its presence for certain purposes, so it's not a bad idea to restore it. – I Hate Lazy Nov 09 '12 at 13:43