【问题标题】:How do I refactor these javascript if else conditional statements in my app?如果我的应用程序中有条件语句,我该如何重构这些 javascript?
【发布时间】:2012-11-13 04:41:06
【问题描述】:

我正在构建一个使用两个滑块的计算器,如下所示:

我有一系列 CPU 和 RAM 数据存储在这样的对象中:

var CloudPlans = {
   small: {

        id: 'small',

        from: {
            cpu: 1,
            ram: 1
        },

        to: {
            cpu: 2,
            ram: 2
        },

        price: {
            linux: 3490,
            windows: 4190
        }
    },

    medium:  {

        id: 'medium',

        from: {
            cpu: 2,
            ram: 2
        },

        to: {
            cpu: 4,
            ram: 4
        },

        price: {
            linux: 5600,
            windows: 6300
        }

    },

    large: {

        id: 'large',

        from: {
            cpu: 4,
            ram: 4
        },

        to: {
            cpu: 6,
            ram: 8
        },

        price: {
            linux: 9500,
            windows: 10200
        }

    },

           [...more configs here]

}

现在根据滑块的位置和值,我必须检查用户选择了哪个计划,然后计算组件的价格。这是检查价格范围的函数:

    checkPlaninRange: function(cpuVal, ramVal) {
        if(cpuVal >= CloudPlan.small.from.cpu && cpuVal <= CloudPlan.small.to.cpu ) {
            return "small";
        } else if (ramVal >= CloudPlan.small.from.cpu && ramVal <= CloudPlan.small.to.cpu) {
            return "small";
        }
    }

如您所见,我将处理几乎无穷无尽的条件列表以返回所选计划。除了条件语句或案例语句之外,还有什么方法可以简化基于代码的这些计划配置的存储或选择?

【问题讨论】:

  • 你有一个条件集合,都是一样的:迭代它们。到目前为止,“id”似乎是多余的。
  • 你确定你的checkPlaninRange 真的做你想做的事吗?除了将ramValcpu 属性进行比较之外,如果仅满足其中一个条件,它确实会返回“小”。
  • 好吧..如果满足 RIGHT 条件,它会返回“大”和“超大”等中的任何一个。
  • 范围是什么样的?它们是否都以一致的(或至少可预测的) 方式递增?如果是这样,那么只需简单的数学计算就可以确定它们在什么范围内。
  • 它们不一致 - 由管理层根据其市场需求决定

标签: javascript refactoring conditional-statements


【解决方案1】:

改用数组:

var CloudPlans = [
   {
        id: 'small',
        from: {
            cpu: 1,
            ram: 1
        },
        to: {
            cpu: 2,
            ram: 2
        },
        price: {
            linux: 3490,
            windows: 4190
        }
    },

    {
        id: 'medium',
        from: {
            cpu: 2,
            ram: 2
        },
        to: {
            cpu: 4,
            ram: 4
        },
        price: {
            linux: 5600,
            windows: 6300
        }
    },
    {
        id: 'large',
        from: {
            cpu: 4,
            ram: 4
        },
        to: {
            cpu: 6,
            ram: 8
        },
        price: {
            linux: 9500,
            windows: 10200
        }
    },
           //[...more configs here]
}

现在您可以简单地遍历CloudPlans

for(int planIdx = 0; planIdx < CloudPlans.length; ++planIdx) {
    var plan = CloudPlan[planIdx];
    if(cpuVal >= plan.from.cpu && cpuVal <= plan.to.cpu  || 
       ramVal >= plan.from.ram && ramVal <= plan.to.ram) {
           return plan.id;
    }
}

【讨论】:

  • 这看起来很有趣。你能告诉我迭代函数的内容是什么样的吗?我会在迭代中做什么?
  • @AmitErandole:当然,看看我的更新。不确定代码是否正确,但你应该明白。顺便说一句,您的原始代码中有 C&P 错误,您现在能发现吗?
  • @AmitErandole "C & P error" 可能是"复制粘贴错误"
【解决方案2】:

好吧,回到这个问题,我想我会投入两分钱......

我会通过使用数组来稍微压缩您的数据存储,因此不再需要 min 值。

var CloudPlans = [
   {    id: 'small',
        maxcpu: 2,
        maxram: 2,
        price: {
            linux: 3490,
            windows: 4190
        }
    }, {id: 'medium',
        maxcpu: 4,
        maxram: 4,
        price: {
            linux: 5600,
            windows: 6300
        }
    }, {id: 'large',
        maxcpu: 6,
        maxram: 8,
        price: {
            linux: 9500,
            windows: 10200
        }
    }, 
    // etc
].reverse(); // reverse it so the highest plan is first

注意.reverse()。我们将从最高层向下进行比较。


然后使用reduce函数:

checkPlaninRange: function(cpuVal, ramVal) {
    return CloudPlans.reduce(function(plan, compare) {
        return cpuVal <= compare.maxcpu && 
               ramVal <= compare.maxram    ? compare : plan;
    }).id; // remove .id to return the entire object
}

或者,如果您想要更高效的东西,请以同样的方式使用 for 循环:

checkPlaninRange: function(cpuVal, ramVal) {
    var plan = CloudPlans[0];
    for (var i = 1; i < CloudPlans.length; i++) {
        if (cpuVal <= CloudPlans[i].maxcpu && 
            ramVal <= CloudPlans[i].maxram    ) {
            plan = CloudPlans[i];
        } else break;
    }
    return plan.id; // remove .id to return the entire object
}

不是很干净,但它可以让你尽早打破循环。


这些很容易通过额外的类似比较来扩展。

【讨论】:

    【解决方案3】:

    您可以使用给定的 val 遍历配置。类似的东西

    var planFrom, planTo, cpuInRange, ramInRange;
    
    for (var plan in CloudPlans) {
       planFrom = plan.from;
       planTo = plan.to;
       cpuInRange = cpuVal >= planFrom.cpu && cpuVal < planTo.cpu;  
       ramInRange = ramVal >= plamFrom.ram...; 
       if (cpuInRange || ramInRange) {
          return plan.id; 
       } 
    }
    

    【讨论】:

      【解决方案4】:

      您可以从中制作更通用的功能:

      function check(plan, values) {
          for (var prop in values)
              if (plan.from[prop] <= values[prop] && plan.to[prop] >= values[prop])
                   return true; // if only one property is met
          return false;
      }
      // yet I guess this is what you want:
      function check(plan, values) {
          for (var prop in values)
              if (plan.from[prop] > values[prop] || plan.to[prop] < values[prop])
                   return false; // if only one property is not met
          return true; // if all properties are met
      }
      

      现在您的 checkPlaninRange 方法可能如下所示:

      checkSmallRange: function(cpuVal, ramVal) {
          if ( check(CloudPlan.small, {cpu:cpuVal, ram:ramVal}) )
              return "small";
      }
      

      当然,您也可以使用它来循环您的云计划:

      getPossiblePlans: function(cpuVal, ramVal) {
          var plans = []
          for (var id in CloudPlans)
              if ( check(CloudPlans[id], {cpu:cpuVal, ram:ramVal}) )
                  plans.push(id);
          return plans;
      }
      

      正如@Tomasz Nurkiewicz 提到的,具有定义循环顺序的数组在这里会更好。 CloudPlans 是一个对象,枚举顺序是未定义的(依赖于实现),因此当它们的范围不明确时,它可能会返回任何计划。

      【讨论】:

        【解决方案5】:

        您可以做的一件简单的事情是(动态地,预先)创建数组,其值代表各自的范围:

        var cpu = ["small", "small", "medium", "medium", "medium", "large"];
        var ram = ["small", "medium", "medium", "medium", "large"];
        

        你会这样使用:

        function checkPlaninRange(cpuVal, ramVal) {
            return cpu[Math.floor(cpuVal)] || "large";
        }
        
        checkPlaninRange(4.2); // "medium"
        

        【讨论】:

        • 那么,如果小计划包含高达 4.5 (MB) 的 ram 大小会怎样?
        • @Bergi - 你可能会使用别的东西。但是如果示例代码具有代表性,那就可以了。
        • 是的,此方法仅适用于有限、小和离散值范围。这不适合 OP,他的管理层可能希望明天提供其他计划,而他不想重写他的代码。
        猜你喜欢
        • 1970-01-01
        • 2020-02-13
        • 2012-08-31
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多