0

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?

Hunter Larco
  • 785
  • 5
  • 17
  • 1
    What is `fooInstance`? What are "children" and "parents" of `Foo`? What is that `bar` method you're calling but not defining? What do you mean by "prototype command"? – Bergi Apr 20 '13 at 19:28
  • Btw, [this answer](http://stackoverflow.com/questions/13418669/javascript-do-i-need-to-put-this-var-for-every-variable-in-an-object/13418980#13418980) might help you to understand the differences between variable and properties. – Bergi Apr 20 '13 at 19:31
  • 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? – Hunter Larco Apr 20 '13 at 19:36
  • OK, I see your problem now. Just searching for a dupe, if I can't find it I'll answer your question – Bergi Apr 20 '13 at 19:38
  • possible duplicate of [Prototype for private sub-methods](http://stackoverflow.com/questions/9982562/prototype-for-private-sub-methods), maybe see also [this](http://stackoverflow.com/a/11146884/1048572) – Bergi Apr 20 '13 at 19:40
  • Hmm I may be missing something, but I'm unsure how that question helps. Essentially the question is how does a sub-method obtain it's parent dynamically. – Hunter Larco Apr 20 '13 at 19:42
  • I have, thank you, i left a comment for you – Hunter Larco Apr 20 '13 at 19:49
  • @HunterLarco: No, it really is the same situation (only that you cannot modify the parent constructor). – Bergi Apr 20 '13 at 19:51

3 Answers3

2

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();
plalx
  • 42,889
  • 6
  • 74
  • 90
  • This is precisely my idea as well, but I am designing an API and find this cumbersome to use as a user. However while the factory method eliminates the annoying need to pass arguments, within my program it logically makes more sense to use the new prefix and i would rather keep things logical for the users. Is it possible for a sub-method to get the original object dynamically? Normally bindings and the use of this could accomplish just that, but because of the nature of a constructor that doesn't apply here... Is there any other way? – Hunter Larco Apr 20 '13 at 19:47
1

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)

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thank you, i guess the problem is that "this" is the only upward relationship between functions and that using a constructor effectively removes it. This is one of those moments where javascript frustrates me. – Hunter Larco Apr 20 '13 at 19:53
0

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.

Willem Mulder
  • 12,974
  • 3
  • 37
  • 62
  • Yes, but once i created more than one fooInstance that method would break. The code needs to be dynamic. Each fooInstance is unique and each bar instance must be able to obtain it's unique parent. – Hunter Larco Apr 20 '13 at 19:38