Hunter Larco
Hunter Larco

Reputation: 780

Prototyping with Javascript Constructors

Consider the Following Example

var Foo = function(){
    this.identity = 'Foo';
};
Foo.prototype.bar = function(){
    this.identity = 'bar';
};
var fooInstance = new Foo(),
    bar = new fooInstance.bar();

Question

Within bar, how may I obtain the fooInstance variable? Is there a way for a child of Foo to recognize its parent as fooInstance? For example, how could I create a function in bar that would return fooInstance. A slight caveat is that bar must by created using the prototype command and cannot simply be nested in Foo to access any Foo instances that way.

My Ideas and Why They Don't Work

It would be possible to rewrite the functions like so

var Foo = function(){
    this.identity = 'Foo';
};
Foo.prototype.createBar = function(){
    var parent = this;
    function bar(){
        this.parent = parent;
        this.identity = 'bar';
    };
    return new bar();
};
var fooInstance = new Foo(),
    bar = fooInstance.createBar();

Yet for the purposes of creating easily readable code i would rather not use this approach if not needed.

Further Clarification

Let me put the question in context. I am prototyping on CanvasRenderingContext2D so that all contexts for the canvas element will contain my new method. Lets call that method foo and assume context is a created canvas context. How create a variable like so "new context.foo()" such that the foo function can use the context variable?

Upvotes: 0

Views: 119

Answers (3)

Bergi
Bergi

Reputation: 665121

how could I create a function in bar that would return fooInstance

If that function is called as a constructor (with new), you can't really do it. The this keyword, the only reference to the "parent" (the object on which you called the method) is set to the new instance in a constructor invocation. You can get the reference only with a closure, for example by creating the constructor in the parent's constructor function (which doesn't work for you) or by returning the constructor from a closure on the prototype (which you nearly got in the second example):

Foo.prototype.getBarCoonstructor = function() {
    var parentFoo = this;
    return function Bar() {
        // constructor things
        // using "parentFoo" reference
    };
};
// Usage:
var bar = new (foo.getBarConstructor()) (); // ugly.

Instead of creating new constructors for every call of getBarConstructor, you better should put it outside of the method and put parentFoo as an argument to it. Your idea was already quite good.

function Bar(parent) {
    // constructor things, referring "parent"
}
Bar.prototype.… = …;

Foo.prototype.createBar = function() {
    return new Bar(this); // passing the Foo instance
};

(@plalx has the same solution, but wrapped in a module closure)

Upvotes: 1

plalx
plalx

Reputation: 43728

If you need to reference the fooInstance object from the bar object, you could use dependency injection like this:

Foo.prototype.bar = function(fooInstance) {
    this.identity = 'bar';
    this.fooInstance = fooInstance;
};

var fooInstance = new Foo(),
    bar = new foo.bar(fooInstance);

You could simplify the creation process by implementing a factory function on Foo.

Foo.prototype.createBar = (function() {
    function Bar(parent){
        this.parent = parent;
        this.identity = 'bar';
    };

    return function () {
        return new Bar(this);
    };
})();

var fooInstance = new Foo(),
    bar = fooInstance.createBar();

Upvotes: 2

Willem Mulder
Willem Mulder

Reputation: 14004

Foo.prototype.bar is simply a function on the prototype Object of Foo. There is no way for that function to know of its 'parent' unless you explicitly define it in its scope chain.

I.e. if you would do

var Foo = function(){
    this.identity = 'Foo';
};
var fooInstance = new Foo();

Foo.prototype.bar = function(){
    console.log(fooInstance); // retrieve from scope
    this.identity = 'bar';
};
bar = new foo.bar();

that would work.

Upvotes: 0

Related Questions