I have a javascript app that I'm developing where I'm building an action tree on the fly and I've found myself in the curious situation of wanting to purposefully introduce a circular dependency. After an initial very hacky attempt, I discovered that JavaScript variable scoping actually introduces a a pretty reasonable way to solve this. I'm still no expert at JavaScript, so I wanted to get some input on best practices. Here is a snippet of working code:
var Step = function(title, instructions, action) {
this.title = ko.observable(title);
this.instructions = instructions;
this.action = action;
};
var Action = function(cancelText, cancelDescription, cancelStep, nextDescription, addText, addStep, continueText, continueStep) {
this.cancelText = cancelText;
this.cancelDescription = cancelDescription;
this.cancelStep = cancelStep;
this.nextDescription = nextDescription;
this.addText = addText;
this.addStep = addStep;
this.continueText = continueText;
this.continueStep = continueStep;
};
var PersonalStep = new Step(
"Contact Information",
"How can we contact you about your awesome assortment of vehicles? Fill out the form below",
new Action(null, null, null, null, null, null, null, null)
);
var AddVehicleStep = new Step(
"Additional Vehicle",
"You have another car? Great, tell us about it too!",
new Action("Cancel",
"No, nevermind about this vehicle.",
PersonalStep,
"Add another vehicle?",
"+ Add",
AddVehicleStep, // This is the weird bit to me
"No, continue on",
PersonalStep)
);
var VehicleStep = new Step(
"Vehicle Details",
"Tell us about your primary vehicle by filling out the form below.",
new Action(null, null, null,
"Add another vehicle?",
"+ Add",
AddVehicleStep,
"No, continue on",
PersonalStep)
);
So in effect, the AddVehicleStep can continuously add additional vehicles when the user chooses the 'Add' action on the form. In most languages (that I'm familiar with, anyways), the AddVehicleStep variable would fail to parse from within its own constructor. This is very strange to me and I would like to learn more about this idiom of JS. Is there a better way to do object trees like this on the fly?
It also got me to thinking, I had been purposefully declaring my step variables in reverse order so they would be parseable. My discovery about referencing the variable in its own constructor led me to believe that this wasn't necessary. But I just tested it and if I move the AddVehicleStep var after the VehicleStep, VehicleStep gets null for its action.addStep. Is there a way to get around this limitation and let my variables be declared in any order? Would using blank declarations and later setting them work? e.g.
var a;
var b;
var a = new Step(b);
var b = new Step(b);
// a should now have the full instantiated object of b within it, right?
// (provided the step constructor assigned it, of course)
This has probably been answered elsewhere, I just haven't found the keyword to bring it up...
Also, I'm using these steps as part of a Knockout.js app which is essentially implementing a dialog/form wizard - I hope the example code stands on its own for posing the conundrum, but in case you were curious.
Update I had this working in a JS fiddle last night. Turns out that there is something about how the js memory is handled between subsequent runs on jsfiddle that caused it work in the particular window I had been working in (Chrome, latest version). However, opening it in a new window or new browser and it stops working.
The really weird part is that I can't replicate the behavior in any browser. Maybe one of my edits had it declared differently and got it lodged in memory somehow. I really wish I could replicate it, just to prove I'm not crazy...
Thanks for the help!
var a = new b('blah', new c(a))doesn't work? Because I've verified that it does work;a.c.ais defined and it does have the circular dependency I'm looking for. Unless it's a Chrome-only thing somehow...