Search code examples
javascriptinheritanceprototypal-inheritancefunction-object

javascript class inherit from Function class


I like that in javascript, I can create a function, and then add further methods and attributes to that function

myInstance = function() {return 5}
myInstance.attr = 10

I would like to create a class to generate these objects. I assume I have to inherit from the Function base class.

In other words, I would like to:

var myInstance = new myFunctionClass()
var x = myInstance()
// x == 5

But I don't know how to create the myFunctionClass. I have tried the following, but it does not work:

var myFunctionClass = function() {Function.call(this, "return 5")}
myFunctionClass.prototype = new Function()
myInstance = new myFunctionClass()
myInstance()
// I would hope this would return 5, but instead I get
// TypeError: Property 'myInstance' of object #<Object> is not a function

I also tried the more complicated (and more proper?) inheritance method found here: How to "properly" create a custom object in JavaScript?, with no more luck. I have also tried using the util.inherits(myFunctionClass, Function) found in node.js. Still no luck

I have exhausted Google, and therefore feel that I must be missing something fundamental or obvious. Help would be greatly appreciated.


Solution

  • Your trying to inherit from Function. This is a right pain to do. I suggest you do the following instead

    Live Example

    var Proto = Object.create(Function.prototype);
    Object.extend(Proto, {
      constructor: function (d) {
        console.log("construct, argument : ", d);
        this.d = d; 
        // this is your constructor logic
      },
      call: function () {
        console.log("call", this.d);
        // this get's called when you invoke the "function" that is the instance
        return "from call";
      },
      method: function () {
        console.log("method");
        // some method
        return "return from method";
      },
      // some attr
      attr: 42
    });
    

    You want to create a prototype object that forms the basis of your "class". It has your generic methods/attributes. It also has a constructor that gets invoked on object construction and a call method that gets invoked when you call the function

    var functionFactory = function (proto) {
      return function () {
        var f = function () {
          return f.call.apply(f, arguments);      
        };
        Object.keys(proto).forEach(function (key) {
          f[key] = proto[key];
        });
        f.constructor.apply(f, arguments);
        return f;
      }
    }
    

    A function factory takes a prototype object and returns a factory for it. The returned function when called will give you a new function object that "inherits" from your prototype object.

    var protoFactory = functionFactory(proto);
    var instance = protoFactory();
    

    Here you create your factory and then create your instance.

    However this isn't proper prototypical OO. we are just shallow copying properties of a prototype into a new object. So changes to the prototype will not reflect back to the original object.

    If you want real prototypical OO then you need to use a hack.

    var f = function () {
      // your logic here
    };
    f.__proto__ = Proto;
    

    Notice how we use the non-standard deprecated .__proto__ and we are mutating the value of [[Prototype]] at run-time which is considered evil.