0

Question:

A seemingly simple question that I've been researching on and off the for past 2 weeks (please go easy as I'm new to all this!):

How does one neatly implement inheritance in JavaScript when using Require.js and the Revealing Module Pattern?


Example:

Here is an example module which is the base class of some type of 'Component':

define('Component', [], function () {
   "use strict";

   var _privateVar = 10;
   var _doPrivateThings = function () {  /* do stuff */ };    
   var init = function () { /* do stuff */ };
   var update = function () {  /* do stuff */ };

   return {
      init : init,
      update : update
   };

});

Next I want to implement CakeComponent which should inherit everything from Component and allow me to edit/add methods and properties:

define('CakeComponent', ['Component'], function (Component) {
   "use strict";
   
   // Setup inheritance
   var CakeComponent = function() {}
   CakeComponent.prototype = new Component();

   // Add/edit methods/properties
   CakeComponent.prototype.newMethod = function () { /* do stuff */ };

   return {
      init : CakeComponent.init,
      update : CakeComponent.update,
      newMethod : CakeComponent.newMethod
   };

});

Firstly, I'm not sure if that makes complete sense, but secondly, my CakeComponent feels a bit gross because now I've got this CakeComponent redundancy everywhere and I've had to 're-reveal' the init and update methods.

I would really prefer something like this (I realise this doesn't make sense, it's really just pseudo-code):

define('CakeComponent', ['Component'], function (Component) {
   "use strict";

   this.extends(Component);
   var newMethod = function () { /* do stuff */ };

   return {
      newMethod : newMethod
   };

});

Any tips or suggestions would really be appreciated. Thanks.


Further Details

  • Maybe I should always be creating a class object within the define wrapper? I've seen people do this but it seemed unnecessary until I came across this problem.
  • Would the .call() method on the function object be useful at all in this context? e.g. using Component.call()
  • @Bergi please see below:

define([], function () {
    "use strict";

    var Component = function () {

        var _privateVar = 10;
        var _doPrivateThings = function () {  /* do stuff */ };
        this.init = function () { /* do stuff */ };
        this.update = function () {  /* do stuff */ };

    };

    return Component;

});
Community
  • 1
  • 1
  • Have you had a look at [How to implement inheritance in JS Revealing prototype pattern?](http://stackoverflow.com/q/9248655/1048572) already? – Bergi Apr 24 '15 at 12:25
  • `new Component();` doesn't seem to work at all, your `Component` is a module object not a class constructor? – Bergi Apr 24 '15 at 12:27
  • @Bergi Yes, I have read that before, thanks, but my problem is really with requirejs, not just inheritance of the RVP, or protected variables. Hmm, I'll look into why it's not working, thanks –  Apr 24 '15 at 15:33
  • 1
    Do you actually want to have classes (instantiable multiple times), or module objects (singletons)? In the first case, you need to `return` the constructor from your `definer` functions, not an object literal as you currently do. If you want to have modules, what do you mean by "inheritance"? – Bergi Apr 24 '15 at 21:32
  • I think I understand what you're saying. I've added a point in the 'Further Details' question of my original post - but the example I added is still returning an object literal. How would I use RMP without returning an object literal? Do I have to use the `prototype` and forego private properties and methods if I want inheritance? –  Apr 25 '15 at 01:05
  • Ah, your new example returns the `Component` constructor, that's better. While you don't have to use the `.prototype`, you better should. You wouldn't return literals from the constructor, but just use `this`. No, you can still use private variables and methods in your constructor. – Bergi Apr 25 '15 at 09:13
  • Oh, so to define private variables and methods I just leave off the `this`? (see updated code in Further Details) –  Apr 25 '15 at 15:23
  • 1
    Yes, exactly that. Now you can extend that pattern by using the prototype for methods that don't need to be privileged, and you can [inherit from the "class" as always](http://stackoverflow.com/a/10898859/1048572) – Bergi Apr 25 '15 at 20:12

1 Answers1

0

I have seen this model used before, called Universal Module Definition:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['Component'], factory);
    } else {
        root.CakeComponent = factory(root.Component);
    }
}(this, function (Component) {
    return {
        newMethod: function(){ /* do stuff */ }
    };
}));

You could try this, which is not "real" inheritance - in case it does not work - depending on environment, you might need to pass the base functions as well, which is a pity:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['Component'], factory);
    } else {
        root.CakeComponent = factory(root.Component);
    }
}(this, function (Component) {
    return {
        init: Component.init,
        update: Component.update,
        newMethod: function(){ /* do stuff */ }
    };
}));

You can read more to this Topic in this fantastic article about the Universal Module Definition

hexerei software
  • 3,100
  • 2
  • 15
  • 19
  • Oh wow, this looks sneaky - what do you mean by depending on the environment? As in browser vs node.js? Would it be better do define a class object (e.g. `var Component = function() { ... }`) within each module do you think? –  Apr 24 '15 at 11:52
  • @JoeRocc right, actually the implementation for node.js would look a bit different. Redefining Component in each module does not sound like a good idea. RequireJS should be able to hook on to this. Have a closer look at this article about the Universal Module Definiton: http://dontkry.com/posts/code/browserify-and-the-universal-module-definition.html. – hexerei software Apr 24 '15 at 14:08
  • @hexeri_software As far as I understood it, that article suggests not using the UMD, but rather picking a single definition and then using a build (browserify) to decide on the final module definition in post production? I'm not sure how that helps? –  Apr 24 '15 at 15:32
  • @JoeRocc The bottom part of the article is a matter of taste, i was referring more to the top. **BUT** try this: here are different global browser, node and commonJS solutions, all requireJS compatible: https://github.com/umdjs/umd – hexerei software Apr 24 '15 at 15:49
  • Thanks for your, though I'm not sure how this helps me with inheritance? @Bergi commented above that I may need to return a constructor from the `define` factory and (I think) use prototypes if I want to get proper inheritance. What are your thoughts on that? I didn't really realise that the 'module' paradigm is more singleton-oriented –  Apr 25 '15 at 01:10
  • @JoeRocc have not had the time to test your special case with UMD, it was just an idea for an approach that is commonly used and as far as i know, you can export anything (objects, functions, etc..) and not restricted to singletons. read more [here](http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/) and [here](https://spring.io/understanding/javascript-modules) – hexerei software May 01 '15 at 19:07