通过JavaScript构造函数引入循环依赖关系
我有一个javascript应用程序,我正在开发中,我正在动态构建一个动作树,我发现自己处于一个奇怪的境地,想要有目的地引入循环依赖。在进行了一次非常粗略的尝试之后,我发现JavaScript变量作用域实际上引入了一种非常合理的方法来解决这个问题。我仍然不是JavaScript方面的专家,所以我想获得一些关于最佳实践的信息。下面是一段工作代码:通过JavaScript构造函数引入循环依赖关系,javascript,scope,circular-dependency,Javascript,Scope,Circular Dependency,我有一个javascript应用程序,我正在开发中,我正在动态构建一个动作树,我发现自己处于一个奇怪的境地,想要有目的地引入循环依赖。在进行了一次非常粗略的尝试之后,我发现JavaScript变量作用域实际上引入了一种非常合理的方法来解决这个问题。我仍然不是JavaScript方面的专家,所以我想获得一些关于最佳实践的信息。下面是一段工作代码: var Step = function(title, instructions, action) { this.title = ko.obser
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的习惯用法。有没有更好的方法可以动态生成这样的对象树
这也让我想到,我有意识地以相反的顺序声明了我的step变量,以便它们可以被解析。我发现在它自己的构造函数中引用变量,这让我相信这是没有必要的。但是我刚刚测试了它,如果我将AddVehicleStep变量移到VehicleStep之后,VehicleStep的操作会得到null
。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内存在JSFIDLE上的后续运行之间是如何处理的,这导致它在我使用过的特定窗口(Chrome,最新版本)中工作。但是,如果在新窗口或新浏览器中打开它,它将停止工作
真正奇怪的是,我无法在任何浏览器中复制这种行为。也许我的一次编辑以不同的方式声明了它,并以某种方式将它保存在内存中。我真的希望我能复制它,只是为了证明我没有疯
谢谢你的帮助 看看下面的代码:
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时:未定义…这不起作用”
这是因为在启动“c”时,“a”未正确启动和引用
在JSFIDLE上试用:
请查看以下代码:
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时:未定义…这不起作用”
这是因为在启动“c”时,“a”未正确启动和引用
在JSFIDLE上试用:
由于步骤可以包含引用同一步骤的操作,我认为最简单的方法是允许自己在构建步骤后添加操作。像这样的
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(...);
但是,如果你开始这样做,你就失去了在不重写代码的情况下总是确定当你设置动作时会发生什么的能力
为什么要这样做?你必须了解操作的顺序以及它是如何影响这里的事情的
在
操作顺序是
c(a)
->result1
b(结果1)
->result2a
获取result2的值
假设
a
(在本地范围内)以前没有被分配,那么c(a)
相当于c(未定义)
,因为步骤可以有引用同一步骤的操作,我认为最简单的方法是允许自己在构建步骤后也添加操作。像这样的
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(...);
但是,如果你开始这样做,你就失去了在不重写代码的情况下总是确定当你设置动作时会发生什么的能力
为什么要这样做?你必须了解操作的顺序以及它是如何影响这里的事情的
在
操作顺序是
c(a)
->result1
b(结果1)
->result2a
获取result2的值
假设以前未分配
a
(在本地范围内),则c(a)
相当于c(未定义)
您可以将对象引用传递给对象构造函数本身,但它总是“未定义”。所以这有点用处。之所以可以这样做,是因为与Java或.NET相比,JS是一种高度动态的语言。通过解释,绑定和验证在运行时进行。JS也在按值传递变量。变量只保存引用,而不保存值。您不能通过将变量指向其他地方来更改已传递的引用。您是说var a=new b('blah',new c(a))
不起作用吗?因为我已经证实它确实有效a.c.a
已定义,它确实具有我正在寻找的循环依赖关系。除非它是Chrome唯一的东西…好吧,今天早上这有点奇怪-请看有问题的编辑。很抱歉,我怀疑你是Hasith,事实证明我的设置有问题,不是你错了。你可以将对象引用传递给对象构造函数本身,但它总是“未定义”。所以这有点用处。之所以可以这样做,是因为与Java或.NET相比,JS是一种高度动态的语言。通过解释,绑定和验证在运行时进行。JS也在按值传递变量。变量只保存refe