我继承了一个用于浏览和配置产品的大型JavaScript(MooTools)应用程序。
其中有一个跟踪产品配置状态的功能。根据产品的状态调用其他功能。
我扩展它以添加一些新功能,但最终在一个大的switch语句中出现了一堆嵌套条件。
我的问题是,你如何重构条件逻辑?是否存在用于跟踪状态的通用(或JS特定)模式/技术?
更新:这是一个伪版本的函数来说明问题:
switchToVariation: function(link) {
// set the variables
// before switch, set state
switch ( nextType ) {
case 'type1':
if ( prevType == 'type1' ) {
if ( nextIsSameVariation ) {
// do stuff
} else {
if ( nextIsSomethingElse ) {
// do stuff
}
// more stuff
}
} else {
// different stuff
}
break;
case 'type2':
if ( prevWasType1 ) {
// stuff
} else {
if (nextIsSameStyle) {
// stuff
}
// more stuff
}
break;
default:
// default stuff
}
// after switch, set state
}
答案 0 :(得分:3)
当然,主要的答案是:将它分解成更小的部分,每件作品都做得很好。
如果没有看到一个例子,很难更具体,但是你说你在一个大的转换声明中有一个“混乱的条件......”这肯定提供了改进的机会:你可以移动内容每个案例都有自己的功能。
如果你这样做,你有两个选择:要么使函数纯粹地使用你传入它们的参数,这往往会使事情更加模块化,或者使函数闭包操纵外部函数中的数据。我认为后者不太理想 - 用于这些的目的 - 但它可能会更快,因此可以“快速获胜”。
说我们原来有:
function myBigFunction() {
var v1, v2, v3;
/* ...set v1, v2, and v3 to various things...*/
switch (condition) {
case foo:
/* ...do lots of stuff involving v1 and v2...*/
break;
case bar:
/* ...do lots of stuff involving v1 only...*/
break;
case charlie:
/* ...do lots of stuff involving v2 and v3...*/
break;
}
}
然后:
第一个选项:完全独立的功能:
function myBigFunction() {
var v1, v2, v3;
/* ...set v1, v2, and v3 to various things...*/
switch (condition) {
case foo:
doFooStuff(v1, v2);
break;
case bar:
doBarStuff(v1);
break;
case charlie:
doCharlieStuff(v2, v3);
break;
}
}
function doFooStuff(v1, v2) {
}
function doBarStuff(v1) {
}
function doCharlieStuff(v2, v3) {
}
...当然,你可能需要让这些函数返回一些然后处理它,例如:
case foo:
v1 = doFooStuff(v1, v2);
break;
...如果doFooStuff
需要更新v1
。如果需要更新v1
和v2
,您可以返回一个数组,或者在传递给v1
的对象上设置v2
和doFooStuff
属性等以下是使用属性的示例:将v1
和v2
属性替换为具有vdata
和v1
属性<的对象(v2
) / em>上:
var vdata = {
v1: "someInitialValue",
v2: "someInitialValue"
};
...然后拨打doFooStuff
:
case foo:
doFooStuff(vdata);
break;
...允许doFooStuff
同时更新v1
和v2
。但要小心,你不想创建一个包含所有myBigFunction
变量的厨房水槽,这会牺牲模块性。
第二个选项:使用闭包并直接使用父函数的数据:
function myBigFunction() {
var v1, v2, v3;
/* ...set v1, v2, and v3 to various things...*/
switch (condition) {
case foo:
doFooStuff();
break;
case bar:
doBarStuff();
break;
case charlie:
doCharlieStuff();
break;
}
function doFooStuff() {
// work with v1 and v2 directly
}
function doBarStuff() {
// work with v1 directly
}
function doCharlieStuff() {
// work with v2 and v3 directly
}
}
请注意,这里,各种子例程是myBigFunction
内的闭包,因此它们可以直接访问所有myBigFunction
的局部变量。这是更模块化的,但不是第一种选择的完全模块化方法。它也像使用全局变量的函数问题的本地版本:副作用很容易引入并且可能导致麻烦。
第一个选项是首选,但如果它不切实际,第二个选项至少可以帮助您使主线逻辑更清晰。当然,两者的结合可能有效。
答案 1 :(得分:2)
我写了一篇answer,用Java中的一个例子来解释它,但它可以很容易地用JavaScript实现。它实质上是将系统建模为有限状态机。