如何在javascript中重构条件逻辑?

如何在javascript中重构条件逻辑?,javascript,refactoring,conditional,Javascript,Refactoring,Conditional,我继承了一个用于浏览和配置产品的大型JavaScript(MooTools)应用程序 其中有一个跟踪产品配置状态的功能。根据产品的状态调用其他函数 我对它进行了扩展,添加了一些新特性,但最终在一个大switch语句中出现了大量嵌套条件 我的问题是,如何重构条件逻辑?是否有跟踪状态的通用(或特定于JS的)模式/技术 更新:下面是该函数的一个伪版本来说明问题: switchToVariation: function(link) { // set the variables //

我继承了一个用于浏览和配置产品的大型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

}

当然,主要的答案是:把它分成更小的部分,每一部分都做得很好

如果不看一个例子,就很难说得更具体,但是你说你有一个“…在一个大的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中闭包是多么容易的一件大事)。