使用重复结果简化嵌套的if / else吗?

时间:2018-12-13 10:24:44

标签: javascript if-statement conditional

我正在尝试简化以下内容:

function handleDirection(src) {
  if (src === 'left') {
    if (inverse) {
      tracker--;
    } else {
      tracker++;
    }
  } else {
    if (inverse) {
      tracker++;
    } else {
      tracker--;
    }
  }
}

减少条件数量。 src始终为'left''right'

13 个答案:

答案 0 :(得分:49)

您可以检查第一次检查的结果。

这是异或检查。

// typeof inverse === 'boolean'

function handleDirection(src) {
    if (src === 'left' === inverse) {
        tracker--;
    } else {
        tracker++;
    }
}

检查按(src === 'left') === inverse的顺序计算表达式:

src === 'left' === inverse
---- first ---             returns a boolean value
--------- second --------- take result of former check & compairs it with another boolean

答案 1 :(得分:18)

function handleDirection(src) {
   var movement = 1;
   if(src === 'left')
     movement = -1;

   if(inverse)
     tracker += movement;
   else
     tracker -= movement;
}

答案 2 :(得分:11)

您甚至可以只用一行代码来完成它:

function getDirectionOffset(src) {
  tracker += (src === 'left' ? 1 : -1) * (inverse ? -1 : 1);
}

答案 3 :(得分:7)

这可以简化为三元表达式,根据状态返回1-1。然后,您可以将其添加到tracker

function handleDirection(src) {
  var delta = (src === 'left' && inverse) || (src !== 'left' && !inverse) ? -1 : 1;
  tracker += delta;
}

然后可以使用@NinaScholz在回答中指出的逻辑进一步简化此操作:

function handleDirection(src) {
  var delta = (src === 'left') === inverse ? -1 : 1;
  tracker += delta;
}

答案 4 :(得分:4)

假设inverse是您一次设置的标志,那么您不必每次都考虑它,就可以计算一次它的影响一次并将其用作是的,这将减少您的代码分支和逻辑。如果要随时进行更改,则可能需要分离计算逻辑,以便重新使用它。

然后,您还可以将移动方向提取到一个独立的函数中,您的handleDirection变得非常简单-您可以根据srcinvert计算出要移动的方向

let tracker = 0;

//extract logic for the movement offset based on direction
function getDirectionOffset(src) {
  return src === 'left' ? 1 : -1;
}

//have a setter for the invert property
function setInverse(isInverse) {
  movementModifier = isInverse ? -1 : 1
}

//declare the variable dependent on the inverse property
let movementModifier;

//initialise movementModifier variable
setInverse(false);

function handleDirection(src) {
  const offset = getDirectionOffset(src) * movementModifier;
  
  tracker += offset;
}


// usage
setInverse(true);

handleDirection("left");
handleDirection("left");
handleDirection("right");

console.log(tracker);

话虽如此,这一切都表明您不应该使用某个函数,或者应该以不同的方式使用它。您可以在一个类中收集所有这些功能,也可以将所有信息传递给功能,因此您没有全局变量。这是该概念的面向对象的示例实现:

class TrackerMover {
  constructor(inverse) {
    this.tracker = 0;
    this.movementModifier = inverse ? 1 : -1
  }
  
  handleDirection(src) {
   const offset = this.getDirectionOffset(src) * this.movementModifier;

    this.tracker += offset;
  }
  
  getDirectionOffset(src) {
    return src === 'left' ? -1 : 1;
  }
  
  getPosition() {
    return this.tracker;
  }
}


//usage
const mover = new TrackerMover(true);

mover.handleDirection("left");
mover.handleDirection("left");
mover.handleDirection("right");

console.log(mover.getPosition())

顺便说一句,另一种选择是不每次都计算运动。您实际上知道每次发生的情况-实际上,您有一个真值表,其中的输入分别为src === leftinverse,而输出则是您修改跟踪的方式。

+--------+------------+--------+
| isLeft | isInverted | Offset |
+--------+------------+--------+
| true   | true       |     -1 |
| true   | false      |      1 |
| false  | true       |      1 |
| false  | false      |     -1 |
+--------+------------+--------+

因此,您只需将桌子放进去。

let tracker = 0;
let invert = false;

const movementLookupTable = {
  "true": { },
  "false": { },
}

//it can be initialised as part of the above expression but this is more readable
movementLookupTable[true ][true ] = -1;
movementLookupTable[true ][false] = 1;
movementLookupTable[false][true ] = 1;
movementLookupTable[false][false] = -1;

function handleDirection(src) {
  const offset = movementLookupTable[src === "left"][invert];

  tracker += offset;
}


// usage
invert = true;

handleDirection("left");
handleDirection("left");
handleDirection("right");

console.log(tracker);

在这种情况下,这可能是一个矫kill过正的方法,但是如果有更多的标志(包括更多的 values 用于标志)和/或最终状态,则此方法可能会有用。例如,也许您想引入四个方向,但是如果trackerupdown,则不必修改。

+-----------+------------+--------+
| direction | isInverted | Offset |
+-----------+------------+--------+
| left      | true       |     -1 |
| left      | false      |      1 |
| right     | true       |      1 |
| right     | false      |     -1 |
| up        | false      |      0 |
| up        | true       |      0 |
| down      | false      |      0 |
| down      | true       |      0 |
+-----------+------------+--------+

如您所见,现在不仅是布尔值,您还可以处理任何值。然后使用表格将invert更改为windDirection,因此,如果移动为left,而windDirectionright,则结果为就像现在一样,但是您可能会以left的方向行进并left前进,因此您要进一步移动 。或者,您可以移动up并且风向为left,这样tracker(此时为X坐标)将被实际修改。

+-----------+---------------+---------+
| direction | windDirection | OffsetX |
+-----------+---------------+---------+
| left      | right         |      -1 |
| left      | up            |       1 |
| left      | down          |       1 |
| left      | left          |       2 |
| right     | up            |      -1 |
| right     | down          |      -1 |
| right     | right         |      -2 |
| right     | left          |       1 |
| up        | up            |       0 |
| up        | down          |       0 |
| up        | left          |       1 |
| up        | right         |      -1 |
| down      | up            |       0 |
| down      | down          |       0 |
| down      | left          |       1 |
| down      | right         |      -1 |
+-----------+---------------+---------+

考虑到四个方向和四个风向,将来的逻辑读取和维护都非常麻烦,而如果您只有查找表,这很容易,并且可以轻松扩展以甚至处理对角线(假设它们通过0.5而不是1来更改值),只要您从表中获取值,您的算法就不会真正在意。

答案 5 :(得分:3)

这只有一个条件,我发现它的读法比其他答案更直观:

function handleDirection(src) {
    if (
        ((src === 'left') && !inverse) ||
        ((src === 'right') && inverse)
    ) {
        tracker++;
    }
    else {
        tracker--;
    }
}

答案 6 :(得分:3)

如果src == leftinverse中的一个为真但不为另一个,则要增加跟踪器,否则要减小跟踪器,这就是“ XOR” ^运算符的作用:

function handleDirection(src) {
    if (src === 'left' ^ inverse) {
        tracker++;
    } else {
        tracker--;
    }
}

您可以通过使用三元表达式进一步降低该值:

function handleDirection(src) {
    tracker += src === 'left' ^ inverse ? 1 : -1;
}

或者,如果您想避免使用隐式强制转换和“聪明”算术的任何条件:

function handleDirection(src) {
    tracker += 1 - 2 * (src === 'right' ^ inverse); // either 1-0=1 or 1-2=-1
}

答案 7 :(得分:3)

您根本不需要任何if句子。可以执行相同的操作 根据 src inverse 计算正或负增量 只需三元运算符的帮助。

function handleDirection(src) {
    tracker += (src == "left" ? 1 : -1) * (inverse ? -1 : 1);
};

顺便说一句。为了提高效率,我建议直接使用数字 递增/递减而不是需要额外处理的字符串 解码。您可以使用常量来实现相同的可读性:

还可以将

inverse 优化为在1(非 倒置)和-1(倒置)。

const left = 1;
const right = -1;
var direction = 1;

function handleDirection(src) {
    tracker += src * direction;
}

function reverse() { // (Example)
    direction = direction * -1;
}

...即使“ right”和“ left”关键字来自某种文本用户 输入,您只需从词典中翻译它们即可:

const steps = {
    left = 1;
    right = -1;
};

function handleDirection(src) {
    tracker += steps[src] * direction;
}

答案 8 :(得分:2)

您可以使用短路语法或三元运算符

// by using short circuiting
    function handleDirection(src) {
       if (src == 'left') tracker = inverse && tracker-1 || tracker +1
       else  tracker = inverse && tracker+1 || tracker -1
    }
// by using ternary operator
 function handleDirection(src) {
       if (src == 'left') tracker = inverse ? tracker-1 : tracker +1
       else  tracker = inverse ? tracker+1 : tracker -1
    }

答案 9 :(得分:2)

我不喜欢别的,如果可能的话,尽量避免嵌套。我认为这更自然地传达了inverse的思想:

function handleDirection(src) 
{
    let change = 1;

    if ('right' == src)
        change = -1;

    if (inverse)
        change = -change;

    tracker += change;
}

答案 10 :(得分:0)

我知道这不是直接用“简化”来直接解决问题,但我想为您提供解决几个代码质量问题,同时也使代码更具可读性的答案。

关于副作用

首先,此给定函数会更改外部值。这引入了side effects的问题:

  • 该功能正在改变外部状态,而外部状态可能无法在外部环境中处理,因此可能导致不确定的行为。
  • 然后函数本身被绑定到外部状态,这使得更改和重构代码变得困难。

要测试这种功能也要困难得多,因为您必须先“创建状态环境”才能运行测试。

第一个简单的调整就是通过参数接受所有外部值,然后只返回分配给任何内容的1-1值(在您的情况下为tracker

带字符串的异或条件

第二,在字符串值上使用if/else时使用互斥或​​会导致未定义状态,其中src可能不是'right'的东西,但函数的行为就像是{ {1}}。相反,它应该引发异常。在这里使用开关是一个很好的帮助。

将这些点应用于功能

如果考虑到以上几点,总体功能将如下所示:

'right'

您可以轻松测试此功能:

function handleDirection (src, inverse) {
  switch (src) {
    case 'left':
      return inverse ? -1 :  1
    case 'right':
      return inverse ?  1 : -1
    default:
      throw new Error(`Unknown src: ${src}`)
  }
}

现在,该功能显然已经与handleDirection('left' , true) // -1 handleDirection('left' , false) // 1 handleDirection('right', true) // 1 handleDirection('right', false) // -1 handleDirection('middle',true) // Error: Unknown src: middle 分离了(考虑到重构时的宝贵时间),而且完全清楚该功能的作用。

注意

总结一下,我想强调一点,并不是总是写最简单的代码且行数最少,而是易于阅读/理解的代码。它不像提供的许多解决方案那么短,但是每个人都应该立即了解它的作用。

答案 11 :(得分:-1)

现在您正在比较字符串,我不建议这样做。例如,如果您使用“左”而不是“左”,它将使第一个if语句失败。布尔可能在这里有用,因为您可以保证它只有两个状态。

其中的if语句可以通过conditional operators进行压缩。

也许您正在寻找这样的东西

function handleDirection(src) {
  if (src) {
    inverse ? tracker-- : tracker++;
  } else {
    inverse ? tracker++ : tracker--;
  }
}

请参阅:https://jsfiddle.net/9zr4f3nv/

答案 12 :(得分:-3)

您可以使用js中的二维数组类型数据结构,并将所需结果存储在sec和inverse索引处。或JSON。