如何在javascript中重构条件逻辑?
我继承了一个用于浏览和配置产品的大型JavaScript(MooTools)应用程序 其中有一个跟踪产品配置状态的功能。根据产品的状态调用其他函数 我对它进行了扩展,添加了一些新特性,但最终在一个大switch语句中出现了大量嵌套条件 我的问题是,如何重构条件逻辑?是否有跟踪状态的通用(或特定于JS的)模式/技术 更新:下面是该函数的一个伪版本来说明问题:如何在javascript中重构条件逻辑?,javascript,refactoring,conditional,Javascript,Refactoring,Conditional,我继承了一个用于浏览和配置产品的大型JavaScript(MooTools)应用程序 其中有一个跟踪产品配置状态的功能。根据产品的状态调用其他函数 我对它进行了扩展,添加了一些新特性,但最终在一个大switch语句中出现了大量嵌套条件 我的问题是,如何重构条件逻辑?是否有跟踪状态的通用(或特定于JS的)模式/技术 更新:下面是该函数的一个伪版本来说明问题: switchToVariation: function(link) { // set the variables //
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
}
当然,主要的答案是:把它分成更小的部分,每一部分都做得很好 如果不看一个例子,就很难说得更具体,但是你说你有一个“…在一个大的switch语句中有一堆条件…”,这无疑提供了一个改进的机会:你可以将每个案例的内容移动到它自己的函数中 如果你这样做,你有两个选择:要么让函数完全使用你传递给它们的参数工作,这会使事情更加模块化,要么让函数闭包来操作外部函数中的数据。我认为后者不太理想——出于这些目的——但它可能更快,因此是一个“快速胜利” 假设我们最初有:
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) {
}
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
}
}
…当然,很可能需要让这些函数返回一些内容,然后再处理这些内容,例如:
case foo:
v1 = doFooStuff(v1, v2);
break;
…如果doFooStuff
需要更新v1
。如果它需要更新v1
和v2
,您可以返回一个数组,或者对传递给doFooStuff
的对象创建v1
和v2
属性,等等。下面是一个使用属性的示例:用对象替换v1
和v2
属性(vdata
)其上有v1
和v2
属性:
…然后调用dofootuff
:
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(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) {
}
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
的局部变量。这是更模块化的,但不是第一个选项的完全模块化方法。这也类似于处理全局变量的函数问题的局部版本:副作用很容易引入,并且会引起麻烦
第一个选项是首选的,但如果不可行,第二个选项至少可以帮助您使主线逻辑更清晰。当然,两者的结合可能会起作用。请查看
不久前,我用Java编写了一个示例来解释它,但它可以很容易地用JavaScript实现。它本质上是将系统建模为一个有限状态机。有很多设计模式可以用来解决嵌套条件过多/过深的问题,但是,一些代码或模型示例首先会有所帮助。感谢指针,JS.state似乎是一个很好的实现:这是一个很好的建议,谢谢!我现在选择了闭包选项,它已经很容易理解了。@melayal:太好了,很高兴这有帮助!您可以在自己的日程表上逐渐保持模块化(JS中闭包是多么容易的一件大事)。