1

Here is a simple example of what I want :

var ConstBuilder = function() {
    var constructor = function() {} ;
    constructor.prototype = {} ;
    return constructor ;
} ;

ConstBuilder.prototype = {
    add : function(name, value) {
        this.prototype[name] = value ;
    }
} ;

var A = new ConstBuilder() ;
A.add('test', function() {
    console.log('test') ;
}) ;

var a = new A() ;
a.test() ;

This code will fail as A is not an instance of ConstBuilder (because A comes from a returned var constructor = function() {} and won't have the methods defined in its prototype (add).

But this would be useful to modify the super constructor's prototype to have things like :

ConstBuilder.prototype.remove = function(name) {
    delete this.prototype[name] ;
} ;

A.remove('test') ;

a.test ; // undefined

Is there a way to have a function as an instance of another ? So this function may implicitely "inherit" all the methods defined in its constructor's prototype.

Or if you have other suggestions, I aim to build modulable constructors - as instances with prototypes are.

Tot
  • 873
  • 2
  • 13
  • 30

3 Answers3

4

Please make sure you have understood the difference between the .prototype property and the internal inheritance-prototype.


The code will fail as A is not an instance of ConstBuilder. Is there a way to have a function as an instance of another?

A is, as every constructor needs to be, a Function. So if you just define your add and remove methods on the Function.prototype, it will work:

Function.prototype.add = function(name, value) {
    this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
    delete this.prototype[name];
};

function A() {}
A.add('test', function(){console.log('test');});
var a = new A();
a.test(); // test

A.remove('test');
a.test; // undefined

There is no possibility however to let a function inherit from something else than Function.prototype - see Can a JavaScript object have a prototype chain, but also be a function?. If you don't want to modify the native Function.prototype object, you still can use the mixin pattern:

var Constr = (function() {
    function add(name, value) {
        this.prototype[name] = value;
    }
    function remove(name) {
        delete this.prototype[name];
    }
    return function mixin(c) {
        c.add = add;
        c.remove = remove;
        return c;
    };
})();

var A = Constr(function() {…});
A.add("test", …);
var a = new A();
a.test(); // test

I aim to build modulable constructors

You could use the builder pattern, as you just have seem to tried.

function ConstBuilder() {
    this.prototype = {};
};

ConstBuilder.prototype = {
    add: function(name, value) {
        this.prototype[name] = value;
    },
    remove: function(name) {
        delete this.prototype[name];
    },
    getConstructor: function() {
        var constructor = function() {};
        constructor.prototype = this.prototype;
        this.prototype.constructor = constructor;
        return constructor;
    }
};

var A = new ConstBuilder().add('test', function() {
    console.log('test');
}).getConstructor();
var a = new A();
a.test(); // test

To remove functions later, you would need to save a reference to the builder.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I thought of `Function.prototype` too but I don't want to modify the generic `Function` object. But your second answer is maybe the best solution, even if I would have prefered to work with the constructor function directly. Now I know there is no other way. :) Thanks ! – Tot Feb 12 '14 at 23:19
  • In-between there is also the mixin pattern which you could apply to give your methods to only a few selected (constructor) functions :-) – Bergi Feb 13 '14 at 00:32
  • That is what I did but there would be no more modulability, and I also have a problem with the context : after having mixed in the methods, I had to bind all of them with the constructor. – Tot Feb 13 '14 at 10:29
  • You might want to ask another question about that :-) – Bergi Feb 13 '14 at 10:31
  • 1
    To be continued here : http://stackoverflow.com/questions/21788187/javascript-better-way-to-modify-function-prototype – Tot Feb 14 '14 at 20:52
  • That question doesn't seem to ask about about mixing in the methods… – Bergi Feb 15 '14 at 20:34
0
function a (x,y,construct)
    {
    if (!construct) return;
    this.x=x;
    this.y=y;
    }

a.prototype.methoda=function ()
    {
    return x+y;
    }

function b (x,y,d,e)
    {
    a.call (this,x,y,true) //--- this would inherit all own Objects and Properties of a and become own properties of b
    this.d=d;
    this.e=e;
    }

  b.prototype=new a ();  //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
  b.prototype.constructor=b;

  var test=new b (1,2,3,4);
  b.methoda ();

second way

function a (x,y)
    {
    if (arguments.callee.doNotConstruct) return;
    this.x=x;
    this.y=y;
    }

a.prototype.methoda=function ()
    {
    return x+y;
    }


function b (x,y,d,e)
    {
    a.call (this,x,y) //--- this would inherit all own Objects and Properties of a and become own properties of b
    this.d=d;
    this.e=e;
    }
  a.doNotConstruct=true;
  b.prototype=new a ();  //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
  a.doNotConstruct=false;

  b.prototype.constructor=b;

  var test=new b (1,2,3,4);
  b.methoda ();

put this in a function

 function prototypeInheritance (inheritor,parent)
 {
 parent.doNotConstruct=true;
 inheritor=new parent ();
 inheritor.prototype.constructor=inheritor;
 inheritor.parent=parent;
 parent.doNotConstruct=false;
 }

you can call the parent property with (arguments.callee.parent) in the inheritor constructor and you can check doNotConstruct with arguments.callee.doNotConstruct in the parent constructor

  • You should not create an instance of Parent to set prototype part of inheritance in Child as this can cause problems. You've solved the problems by returning if no construct parameter is passed. Nice and creative but now you have to pass this every time you create an instance. To set up prototype part you could use Object.create and use polyfil if you want to support older browsers. – HMR Feb 13 '14 at 00:13
  • Sorry HMR , I'm a programmmer in Javascript since 2002, i do that this way all the time and had no problems. every constructor has a construct attribut it's something that's routine. Object.create is new and not supported in older browsers. –  Feb 13 '14 at 06:58
  • Object.create was/is used in the closure library for many years. At least the polyfil that takes one argument. It's a nice way to solve getting only the prototype part but personally would find it inconvenient to have to pass an extra argument to every constructor every time I would like to create an instance. – HMR Feb 13 '14 at 07:28
  • You can also add a property to the constructor function constructor.doNotConstruct=true then change the if statement to if (arguments.callee.doNotConstruct) return; and set doNotConstruct property before you make inheritance on the prototype and then reset it...... i'm not sore if closure library exactly can clone the prototype .... what is if you have properties which have get or set functionallity defined by Object.defineProperty in the prototype –  Feb 13 '14 at 19:56
  • Object.create doesn't clone. It returns argument 2 or empty object with argument 1 as it's prototype. What goog.inherits and the MDN polyfil does is exactly that. Except they don't support second argument. Setting construct property to false does exactly the same, return an empty object with the constructor prototype as it's prototype. – HMR Feb 14 '14 at 00:56
  • If you provide second argument (object define property) the mdn polyfil throws an error. For setting Child prototype you don't need the second argument. The second argument is Child constructor. Unless you don't support older browsers and plan to use defineProperty but in that case you don't need the polyfil anyway – HMR Feb 14 '14 at 00:58
0

I think that you are looking for an example of how to do JavaScript's "prototypical inheritance". When JavaScript looks for a property on an object, it first checks the object itself. Next it checks the prototype. However, since everything in JavaScript is an object and the prototype is an object

function Root(){}
Root.prototype.fromRoot = function() { console.log("I'm on Root's prototype."); };
function Child(){}
Child.prototype = new Root();
Child.prototype.fromChild = function() { console.log("I'm on Child's prototype."); };

var r = new Root();
var c = new Child();

r.fromRoot();  // works
c.fromRoot();  // works
c.fromChild(); // works
r.fromChild(); // fails
squid314
  • 1,394
  • 8
  • 9
  • Bad example, you're creating in instance of Parent to set prototype part of inheritance of Child and you don't re use Parent cosntructor code by having `Parent.call(this,args);` in Child's body. Even though not needed because there are no instance members in this case. In normal cases you'd want to re use Parent constructor code and your example doesn't show how. – HMR Feb 13 '14 at 00:09