landunder
landunder

Reputation: 382

Circular reference instantiation

I want to instantiate two classes which both depend on each other like so:

this.a = null;
this.b = null; 
this.a = new A({
  b: this.b
}
this.b = new B({
  a: this.a
}

The problem is if I do so b is null if I hand it to the constructor. How can I solve this chicken or the egg problem in an "elegant" way? Or do I have to set the reference to b after the instantiation via a method?

Upvotes: 1

Views: 127

Answers (1)

Siguza
Siguza

Reputation: 23850

I suggest moving the problem to the constructors of A and B.

You can leverage conditional (indirect) recursion in this case:

function A(b)
{
    this.b = b || new B(this);
}
function B(a)
{
    this.a = a || new A(this);
}

By using ||, you ensure that a call to A(this) and B(this) will not themselves create another B/A respectively, thus ending the "chicken/egg" problem.

Then you can use them like

this.a = new A();
this.b = this.a.b;

or

this.b = new B();
this.a = this.b.a;

If there are cases where A or B legitimately have their .b or .a set to null, you could use undefined and null to distinguish those cases, and change the constructors accordingly:

function A(b)
{
    this.b = b === undefined ? new B(this) : b;
}
function B(a)
{
    this.a = a === undefined ? new A(this) : a;
}

If A and B require other arguments to their constructor, or should for some other reason not construct another B or A themselves, you could pass them the this instance from the creating scope (since that holds a and b fields, whose value will be determined only when accessed, not when A and B are constructed):

function A(container)
{
    this.container = container;
    // Access B via this.container.b
}
function B(container)
{
    this.container = container;
    // Access A via this.container.a
}
this.a = new A(this);
this.b = new B(this);

If A and B are not meant to have full access to the container object, you could create intermediary objects to be used in its place, like:

var aProxy = { a: null };
var bProxy = { b: null };
this.a = aProxy.a = new A(bProxy);
this.b = bProxy.b = new B(aProxy);

If that is also unacceptable for some reason, then your only option is to later change the value of a.b and b.a by means of manual assignment or via a setter function.

Upvotes: 1

Related Questions