我有一个javascript应用程序,我正在开发我正在动态构建一个动作树,我发现自己处于想要有目的地引入循环依赖的奇怪情况。在最初非常hacky尝试之后,我发现JavaScript变量范围实际上引入了一种非常合理的方法来解决这个问题。我仍然不是JavaScript的专家,所以我想得到一些关于最佳实践的意见。这是一段工作代码:
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)
);
因此,当用户在表单上选择“添加”操作时,AddVehicleStep可以不断添加其他工具。在大多数语言中(无论如何我都很熟悉),AddVehicleStep变量无法在自己的构造函数中解析。这对我来说很奇怪,我想更多地了解这个JS的习语。有没有更好的方法可以在运行中像这样做对象树?
它还让我思考,我一直故意以相反的顺序声明我的步骤变量,因此它们是可解析的。我在自己的构造函数中引用变量的发现让我相信这不是必要的。但我只测试了它,如果我在VehicleStep之后移动AddVehicleStep var,则VehicleStep为其null
获取action.addStep
。有没有办法解决这个限制,让我的变量以任何顺序声明?是否会使用空白声明并稍后设置它们? 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)
这可能已在其他地方得到解答,我只是没有找到关键字来提起它......
此外,我正在使用这些步骤作为Knockout.js应用程序的一部分,该应用程序本质上是实现一个对话框/表单向导 - 我希望示例代码能够独立地构成一个难题,但是如果您感到好奇的话。
更新 我昨晚做了一个JS小提琴。事实证明,在jsfiddle的后续运行之间有一些关于如何处理js内存的问题导致它在我工作过的特定窗口中工作(Chrome,最新版本)。但是,在新窗口或新浏览器中打开它会停止工作。
真正奇怪的部分是我无法在任何浏览器中复制行为。也许我的一个编辑声明它的声明不同,并以某种方式将它记录在内存中。我真的希望我可以复制它,只是为了证明我没有疯狂......
感谢您的帮助!
答案 0 :(得分:2)
看看下面的代码:
function b(data, ref) {
alert("instantiated B with : " + data + " and " + ref);
}
function c(ref){
alert("instantiated C with : " + ref + " ... this doesnt work");
}
var a = new b('blah', new c(a));
'b'已正确初始化。但是提醒您初始化'c'如下:
“实例化C with:undefined ...这不起作用”
这是因为在'c'启动时,'a'不会被启动并正确引用。
试试jsfiddle:
答案 1 :(得分:2)
由于步骤可以包含引用相同步骤的操作,因此我认为在构建步骤之后允许自己添加操作的能力最简单。所以,就像这样。
var Step = function(title, instructions, action) {
this.title = ko.observable(title);
this.instructions = instructions;
if (action === undefined)
this.action = null; //action was not passed
else
this.action = action;
};
//set the action after constructor invocation
Step.prototype.SetAction = function(action) {
this.action = action;
};
var AddVehicleStep = new Step(
"Additional Vehicle",
"You have another car? Great, tell us about it too!"
);
//AddVehicleStep is now instantiated with a new Step,
// so we can now set its action refering to that step
AddVehicleStep.SetAction(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));
或者地狱,忘记方法并直接进行
AddVehicleStep.action = new Action(...);
但是如果你开始这样做,你就无法总是在不重写代码的情况下确定在设置动作时会发生什么。
为什么这样?你必须了解操作的顺序以及这对事物的影响。
in
a = b(c(a))
操作顺序是
c(a)
- > result1
b(result1)
- > result2 a
获取result2
假设之前未分配a
(在本地范围内),则c(a)
相当于c(undefined)