【问题标题】:Avoiding Repetition in Nested Conditional避免嵌套条件中的重复
【发布时间】:2013-10-02 14:18:06
【问题描述】:

使用类似于以下的嵌套条件,您如何优化分支以提高性能和/或可读性?由于许多潜在案例中存在循环,因此将重复条目合并为更实用的函数会更有效。

//a is defined either 1, 2, or 3
//b is defined either true or false

for(var i=0; i<hugeNumber; i++){
switch(a){
    case 1:
        if(b){
            for(objects in longlist){
                objects.color = object.c;
                objects.position = object.x
            }
        }else{
            for(objects in longlist){
                objects.color = object.c;
                objects.position = object.y
            }
    case 2:
        if(b){
            for(objects in longlist){
                objects.color = object.b;
                objects.position = object.x;
            }
        }else{
            for(objects in longlist){
                objects.color = object.b;
                objects.position = object.y;
            }
    case 3:
        if(b){
            for(objects in longlist){
                objects.color = blackColor;
                objects.position = object.x;
            }
        }else{
            for(objects in longlist){
                objects.color = blackColor;
                objects.position = object.y;
            }
}
}

将条件放在一个总体 for 循环中似乎同样不合理。

理想情况下,目标变量可以在开始时立即定义,当条件已知时 - 条件 a 总是产生颜色 c 为 0,颜色 b 为 1,黑色颜色为 2,而条件 b 总是产生位置 x 为真和位置 y 为 false。

我已经看到这个问题针对 PHP 和 Ruby 的变体,但不太确定如何将这些解决方案应用于 JavaScript。我可以想出一些可行的方法,但到目前为止我还不能使代码在语法上起作用。

更新/解决方案:一个答案促使我发现这可以通过eval() 有效地完成:

var targetColor;
var targetPosition;

switch(a){
    case 1: targetColor = "objects.c"; break;
    case 2: targetColor = "objects.b"; break;
    case 3: targetColor = "blackColor"; break;
}
if(b){
    targetPosition = "objects.x";
}else{
    targetPosition = "objects.y";
}

for(var i=0; i<hugeNumber; i++){
    for(objects in longlist){
        objects.color = eval(targetColor);
        objects.position = eval(targetPosition);
    }
}

如果有比这更好的方法,我绝对愿意接受其他建议 - 我知道 eval 有时可能很危险。

【问题讨论】:

  • object.cobject.x 是什么?它们是longlist 对象中的属性吗?
  • 没错——它们是对象的属性。
  • 请在for (objects in longlist){... 部分之一中显示代码。
  • @thefourtheye 已更新 - 使用 cmets 肯定会混淆手头的问题,谢谢。
  • 谢谢 :) 无论如何要小心eval,只有在您确定将什么作为字符串传递给它时才使用它(例如,查看闭包链并评估添加正则表达式的可能性必要时检查字符串的内容)

标签: javascript optimization code-readability


【解决方案1】:

不那么紧凑,但可读性很好,没有不必要的重新检查:

var coord = b ? 'x' : 'y';
var col = '';
switch(a){
    case 1: col = 'c';
    case 2: col = 'b';
    // may add more cases...
}
for(objects in longlist) {
    object.color = object[col] || 'blackColor';
    object.position = object[coord];
}

【讨论】:

  • 我将此标记为正确的解决方案,因为它考虑到对象自身的属性,而不是全局变量,决定了它使用的值。这个答案也促使我使用eval() 作为该问题的当前解决方案(请参阅更新的问题)。谢谢!
【解决方案2】:
var colorToBeApplied = (a === 0 ? "c" : (a === 1 ? "b" : "blackColor"));
var position = b ? "x" : "y";

for(objects in longlist) {
    objects.color    = colorToBeApplied;
    objects.position = position;
}

如果你可以在for循环中显示代码,那就更好了。

【讨论】:

  • 这是有道理的,但是在另一个三元运算符的“else”块内使用三元运算符不是很可读。我会为此使用if 声明。
  • @ThomasUpton 我其实在想var colorToBeApplied = a === 1 || a === 0 ? String.fromCharCode('c'.charCodeAt(0) - a) : "blackColor";
  • 这样做的问题是每个对象的objects.color 应该设置为其对应的objects.cobjects.b,而不是全局变量cb。像objects.color = objects[colorToBeApplied] 这样的东西会起作用,但对于objects.color = blackColor
【解决方案3】:

使用您所描述的逻辑,我发现这是在最少的行数和可读性之间的一个不错的地方。

for(objects in longList) {
    object.pos = b ? x : y;
    switch(a) {
        case 1: object.color = c;
        case 2: object.color = b;
        case 3: object.color = backColor;
    }
}

这有意义吗?

【讨论】:

  • 我更新了问题以使其更清楚 - cmets 的使用可能具有误导性。您的解决方案当然可以压缩代码,但请考虑以下问题:问题在于每个对象的 objects.color 应设置为其对应的 objects.cobjects.b,而不是全局变量 c 或 @987654326 @。像objects.color = objects[colorToBeApplied] 这样的东西会起作用,但对于objects.color = blackColor
  • 我的解决方案不应该仍然有效吗?只需替换全局变量即可使用object 的属性。
  • 我担心这个解决方案过于密集,因为必须检查长列表中的每个对象的大小写。由于案例是在开始时定义的,我正在寻找某种方法来首先确定要使用哪些变量,然后循环遍历对象并适当地设置它们的值。我用“模拟”解决方案再次更新了这个问题。再次感谢您的反馈,这似乎是我没有正确表达问题的错。
猜你喜欢
  • 2017-02-05
  • 2020-09-27
  • 1970-01-01
  • 2018-11-13
  • 1970-01-01
  • 2020-04-01
  • 2021-04-28
  • 2012-10-05
相关资源
最近更新 更多