【问题标题】:How to reduce if/else complexity?如何降低 if/else 复杂性?
【发布时间】:2018-05-03 12:37:59
【问题描述】:

我有一些嵌套的 if/else 语句,但我想减少它们的开销。

在示例中,我正在评估从哪个下拉列表中单击了 li 项,以及该 li 项是否是第一个 (currentIndex === 0)。

代码:

if (parentIndex === 1) {
  // But its own index is 0
  if (currentIndex === 0) {
    parentIndex = 2;
    updatedIndexPos = array[1];
    mainIndex =list_2.indexOf(updatedIndexPos);
    // If the previous line is -1:
    if (mainIndex === -1) {
      parentIndex = 1;
      updatedIndexPos = filterIndexPos;
      mainIndex = list_1.indexOf(updatedIndexPos);
    }
  } else {
    mainIndex = list_1.indexOf(mainIndexPos);
  }
} else if (parentIndex === 2) {
  // But its own index is 0
  if (currentIndex === 0) {
    parentIndex = 1;
    updatedIndexPos = array[0];
    mainIndex = list_1.indexOf(updatedIndexPos);
    // If the previous line is -1:
    if (mainIndex === -1) {
      parentIndex = 2;
      updatedIndexPos = filterIndexPos;
      mainIndex = list_2.indexOf(updatedIndexPos);
    }
  } else {
    mainIndex = list_2.indexOf(mainIndexPos);
  }
}

看着它有很多重用的代码,而 eslint 给了我 7 的复杂度。我已经尝试将它分解成更小的函数并传递参数,但仍然没有设法解决这个代码块的复杂性。

【问题讨论】:

标签: javascript jquery if-statement cyclomatic-complexity


【解决方案1】:

将逻辑建模为state-machine 通常很有帮助。 所以你已经定义了它们之间的状态和转换。

var action = 'foo';
var actionParams = {...};
var currentState = getState({parentIndex: parentIndex, ...});
if (currentState.canPerform(action)) {
  currentState.perform(action, actionParams);
}

【讨论】:

    【解决方案2】:

    尝试提取常见部分,例如(未经测试):

    if (parentIndex === 1) {
      potentialNewParent = 2;
      potentialUpdatedIndexPos = array[1];
      nullParentIndex = 1;
      mainList = list_1;
      otherList = list_2;
    } else {
      // Do the same
    }
    
    if (currentIndex === 0) {
      parentIndex = potentialNewParent;
      updatedIndexPos = potentialUpdatedIndexPos;
      mainIndex = mainList.indexOf(updatedIndexPos);
      // If the previous line is -1:
      if (mainIndex === -1) {
        parentIndex = nullParentIndex;
        updatedIndexPos = filterIndexPos;
        mainIndex = otherList.indexOf(updatedIndexPos);
      }
    } else {
      mainIndex = otherList.indexOf(mainIndexPos);
    }
    

    【讨论】:

    • 谢谢埃文 - 我会试试你的解决方案。我一直试图将这些共同点放在一起,但这看起来更像
    • 以上内容未经测试,只是为了展示大致思路。
    • 我实现了一个工作版本,但 eslint 仍然使用嵌套的 if (mainIndex === -1) {...} 语句来吸引我!
    • 在警告你之前的默认最大复杂度是 20,我认为你对 linting 的设置太严格了。
    • 你可以把它分解成函数,在这一点上它有点武断。
    【解决方案3】:

    假设 parentIndex 始终为 1 或 2,则可以简化很多。因为我不知道它应该做什么,所以我没有对此进行测试,变量名可能不合适:

    const mainList = parentIndex === 1 ? list_1 : list_2;
    const secondaryList = parentIndex === 1 ? list_2 : list_1;
    
    if (currentIndex === 0) {
      parentIndex = parentIndex === 1 ? 2 : 1;
      updateIndexPos = array[parentIndex - 1];
      mainIndex = secondaryList.indexOf(updatedIndexPos);
      if (mainIndex === -1) {
        parentIndex = parentIndex === 1 ? 2 : 1;
        updatedIndexPos = filterIndexPos;
        mainIndex = mainList.indexOf(updatedIndexPos);
      }
    } else {
      mainIndex = mainList.indexOf(mainIndexPos);
    }
    

    【讨论】:

    • 感谢 Fin,此功能的 parentIndex 始终为 1 或 2。我目前正在尝试在下面实现@Evan Trimboli 的答案,但也会看看这个
    • 貌似大抵是一样的解决方案,我只是用三元运算比他的代码省了16行代码。并不是说节省线总是好的,但我想说在这种情况下它是。
    【解决方案4】:

    假设 parentIndex 只能是 1 或 2,这对你有用吗?

    var elements = [2, 1];
    if ((parentIndex === 1 || parentIndex === 2) && currentIndex === 0) {
    
      oldParentIndex = parentIndex;
      parentIndex = elements[oldParentIndex-1];
      updatedIndexPos = array[oldParentIndex%2];
      mainIndex = this["list_"+parentIndex].indexOf(updatedIndexPos);
    
      if (mainIndex === -1) {
        parentIndex = oldParentIndex;
        updatedIndexPos = filterIndexPos;
        mainIndex = this["list_"+oldParentIndex].indexOf(updatedIndexPos);
      }
    } else if ((parentIndex === 1 || parentIndex === 2) && currentIndex !== 0) {
      mainIndex = this["list_"+parentIndex].indexOf(updatedIndexPos);
    }
    

    【讨论】:

    • 为此使用 eval 是完全不必要的,也是一个坏主意。 stackoverflow.com/questions/86513/…。 this["list_"+parentIndex] 也应该这样做。
    • @FINDarkside 它仍然是一个可行的解决方案,不是最好的,但可行。您能帮我了解一下 eval() 是如何造成安全问题的吗?
    • eval 会运行你给它的代码。如果你执行 eval(username),我可以通过更改我的用户名在每个人的浏览器上运行我想要的任何代码。虽然这个特定的代码不包含用户生成的内容,但它仍然是非常错误(而且速度很慢)的工具。 this["list_"+parentIndex] 是正确的做法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 2021-09-08
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    相关资源
    最近更新 更多