2

I'm having troubles finding detailed information on this issue. I would like to instantiate Bar() within Foo() without having to pass a pointer to Foo(). Or some way for Bar() to know it's a child of Foo(). Is this possible? Or am I already using a sufficient method?

Basically, I'm trying to avoid a call like:

var bar1 = new Bar(this,someValue);

Below I have a rough example of the method I'm currently using.

function Bar(p,val) {
    var par = p,
        value = val;
    this.__defineGetter__("value", function() {
        return par.dun.value + value;
    });
}

function Dun(val) {
    var value = val;
    this.__defineGetter__("value", function() {
        return value;
    });
}

function Foo() {
    var dun = new Dun(15);
    var bar1 = new Bar(this, 10);
    var bar2 = new Bar(this, 20);
    this.__defineGetter__("dun", function() {
        return dun;
    });
    this.__defineGetter__("bar1", function() {
        return bar1;
    });
    this.__defineGetter__("bar2", function() {
        return bar2;
    });
}
var myFoo = new Foo();
myFoo.bar1.value;

Thanks.

Duncan
  • 1,530
  • 15
  • 20

3 Answers3

2

No this is not possible, since there is no built in parent/child logic in JavaScript. They are just references to objects.

Update

oh sorry, I think I misunderstood your question. I´ve asked the same question some time ago: here. What you are trying to do, is to get the object that is "this" in the function that called the current function.

The answer is: you can´t do it...

But you could do it using the scope:

function Dun(val) {
    var value = val;
    this.__defineGetter__("value", function() {
        return value;
    });
}

function Foo() {
    var dun = new Dun(15);
    var bar1 = new Bar(10);
    var bar2 = new Bar(20);
    this.__defineGetter__("dun", function() {
        return dun;
    });
    this.__defineGetter__("bar1", function() {
        return bar1;
    });
    this.__defineGetter__("bar2", function() {
        return bar2;
    });
    function Bar(val) {
        this.__defineGetter__("value", function() {
            return dun.value + val;
        });
    }
}
var myFoo = new Foo();
myFoo.bar1.value;

PS: Not related to your question, but nice to know: since

function(val){}

is the same as

function(){
    var val = arguments[0];
}

you don`t have to create a new var and pass the arguments value to it. You can use the argument variable directly.

Community
  • 1
  • 1
Van Coding
  • 24,244
  • 24
  • 88
  • 132
  • So, I should just stick to the way I'm doing it now? :) – Duncan Sep 14 '11 at 16:33
  • Yes, either that, or you define Bar inside of Foo and then use the scope to access it. – Van Coding Sep 14 '11 at 16:37
  • @Duncan, I've shown you one other way to do it in my new answer (which I'm not sure is better than just passing `this` to the constructor), but it's another option to look at. – jfriend00 Sep 14 '11 at 16:41
  • I wasn't aware that you could declare a 'class' inside of a 'class' in JavaScript... That may be exactly what I was looking for! :) – Duncan Sep 14 '11 at 17:46
  • @Van Coding, just an update: Turns out that was perfect, using the scope worked out beautifully. Thank you. – Duncan Oct 22 '11 at 16:12
1

There is no way to automatically know the this pointer of the caller of a new. So, if you want to know what that this value is without passing it as part of the constructor, then you'd have to set some semi-global state that contains the appropriate information. You could do so like this:

function Bar(val) {
    var par = Bar.parent(),
        value = val;
    this.__defineGetter__("value", function() {
        return par.dun.value + value;
    });
}

// global methods and state on the Bar function
Bar.createContext = [];
Bar.push = function(o) {Bar.createContext.push(o);}
Bar.pop = function() {Bar.createContext.pop();}
Bar.parent = function() {return(Bar.createContext[Bar.createContext.length - 1]);}

function Dun(val) {
    var value = val;
    this.__defineGetter__("value", function() {
        return value;
    });
}

function Foo() {
    Bar.push(this);               // set global state
    var dun = new Dun(15);
    var bar1 = new Bar(10);       // don't need to pass "this" since it's in the global state
    var bar2 = new Bar(20);
    this.__defineGetter__("dun", function() {
        return dun;
    });
    this.__defineGetter__("bar1", function() {
        return bar1;
    });
    this.__defineGetter__("bar2", function() {
        return bar2;
    });
    Bar.pop();                    // restore global state
}
var myFoo = new Foo();
myFoo.bar1.value;

And, you can see it work here: http://jsfiddle.net/jfriend00/wMgBL/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

You need to give the child object one of the following:

  1. A direct pointer from one object to another, as in your example code.

  2. Unique information about the parent object, such that it can determine what that parent is indirectly through other means.

    For example, you could store all instances of Foo in a global registry object (either an object literal or array), which the child bar object could search through. It would be looking for the object that has a child bar equal to itself.1 In this way, the fact that it is a child of Foo is the unique identifier. Unless, of course, one bar can be shared across multiple foos. Then you're hosed. :)


1: The downside to this is that you're storing every instance of Foo ever created, which means they'll never be garbage collected: you'll be leaking memory, which could be bad if your environment sticks around for a while (e.g. a node.js app).

Community
  • 1
  • 1
Nick Husher
  • 1,909
  • 11
  • 13