如何评估带有大量 && 和 || 的 If 语句状况

Posted

技术标签:

【中文标题】如何评估带有大量 && 和 || 的 If 语句状况【英文标题】:How to Evaluate If Statements with a lot of && and || Conditions 【发布时间】:2016-07-30 05:01:01 【问题描述】:

我发现了一些类似这样的js 代码:

if (
  (condition 1) && 
  (condition 2 ==  condition 3) && 
  (
    (condition 4 && condition  5) && 
    (condition 6 == condition 7) || 
    (
      (condition 8 && condition 9) && 
      (condition 10 == condition 11)
    ) 
  )
)

如果表达式 (condition 4 && condition 5) 的计算结果为 false,则以下代码的计算结果是否为 truefalse?为什么它评估为truefalse?试图了解如何使用 &&|| 语句的混合来阅读 if 语句。我认为这也可能,但如果有办法重构此代码,请告诉我。

【问题讨论】:

除非变量为真或假,否则它不会返回真或假... @dandavis 这是不真实的。在 javascript 中,除了字面值之外,每个值也都具有真实性。例如,if ("am I truthy") alert("THE TRUTH!"); 将执行警告框。 @OzBarry:我的意思是 OP 的 IF 并不总是 false,因为 4/5 是 false。很多人认为x=(0 && 1 || 0) 会是false,因为0 && 1 会在心里读到“不正确”,但整体实际上是“0 else 0”,所以结果是0;基准结果而不是比较结果。至于IF里面的表达式值,false和falseys(如0)都会有同样的效果... @dandavis 哦,对不起,我误解了你原来的说法。 【参考方案1】:

括号优先 && 优先于 ||

在MDN 和这个SO question 上查看javascript 中的运算符优先级

如果(condition 4 && condition 5)false,结果仍将取决于(condition 8 && condition 9) && (condition 10 == condition 11)

if(
    (condition 1) 
    && (condition 2 ==  condition 3) 
    && (                                  --> false && x || x --> false || x = x
        (condition 4 && condition  5)  
            && (condition 6 == condition 7) 
            || 
            (
                (condition 8 && condition 9) 
                && (condition 10 == condition 11)
            ) 
    )
)

这是否可以重构:绝对。如何?取决于条件和逻辑。

【讨论】:

【参考方案2】:

就个人而言,我将其分解为变量。

var isAEqualToB = a === b
var isCEqualToD = c === d
var isEEqualToA = e === a
var isAOrDTruthy = a || d

var isEEqualToAAndAOrDTruthy = isEEqualToA && isAOrDTruthy

if ((isAEqualToB || isCEqualToD) && isEEqualToAAndAOrDTruthy) 
  // Do your thing here

很多人认为行数越少就是好代码的标志,但它绝对不是。可读性和可维护性对于每个必须处理任何代码的开发人员来说都更有意义。

将条件分解为易于理解的变量(即使用描述条件的变量名称),并将其简化为更简单的东西。您可能会发现将您的全部条件分解为更小的函数也可能会有所帮助。

所以让我们做另一个更有意义的布尔方程。假设我们只想在以下情况下执行一段代码:

早上 6 点到下午 2 点之间 skyColor 的值为 'grey' 您的名字是“ozbarry”或“web-dev” n 的值为 2 或 999

根据您当前的示例,我们将从以下内容开始:

var skyColor = 'grey';
var name = 'ozbarry';
var n = 2;

if (
  // Condition 1, time is between 6am and 2pm
  ((new Date()).getHours() >= 6 && (new Date()).getHours() <= 14) &&

  // Condition 2, skyColor is 'grey'
  (skyColor === 'grey') &&

  // Condition 3, name is either 'ozbarry' or 'web-dev'
  (name == 'ozbarry' || name == 'web-dev') &&

  // Condition 4, n is either 2 or 999
  (n == 2 || n == 999)
) 
  // Do a thing here

这将做正确的事情,但维护起来将是一场噩梦,这是一个非常基本的示例。让我们进行一些重构!

首先,让我们将其中一些条件放入变量中,以便更好地跟踪它们,并删除 cmets,因为变量名称将反映我们正在测试的内容:

var skyColor = 'grey';
var name = 'ozbarry';
var n = 2;

var isHourBetween6And14 = (new Date()).getHours() >= 6 && (new Date()).getHours() <= 14;
var isSkyGrey = skyColor === 'grey';
var isNameValid = name === 'ozbarry' || name === 'web-dev'
var isN2Or999 = n === 2 || n === 999

if (
  isHourBetween6And14 &&
  isSkyGrey &&
  isNameValid &&
  isN2Or999
) 
  // Do a thing here

这样比较好,但还是有一些问题。从代码的角度来看,有些条件仍然很长或不清楚。我主要看isHourBetween6And14,但最后两个也可以用一些注意力,所以让我们把它们分解成有意义的函数:

function isNumberBetween(value, min, max) 
  return value >= min && value <= max


function isValueOneOf(value, validValues) 
  for(validIdx=0; validIdx < validValues.length; validIdx++) 
    if (validValues[validIdx] === value) 
      return true;
    
  
  return false;


var skyColor = 'grey';
var name = 'ozbarry';
var n = 2;

var isHourBetween6And14 = isNumberBetween((new Date()).getHours(), 6, 14)
var isSkyGrey = skyColor === 'grey';
var isNameValid = isValueOneOf(name, ['ozbarry', 'web-dev']);
var isN2Or999 = isValueOneOf(n, [2, 999])

if (
  isHourBetween6And14 &&
  isSkyGrey &&
  isNameValid &&
  isN2Or999
) 
  // Do a thing here

最后,我喜欢做的一件事是在 if 语句之前加入长条件。这将使您的条件更具可读性,而未来的开发人员不需要每次都在心里做逻辑来知道它是否会执行该块:

function isNumberBetween(value, min, max) 
  return value >= min && value <= max


function isValueOneOf(value, validValues) 
  for(validIdx=0; validIdx < validValues.length; validIdx++) 
    if (validValues[validIdx] === value) 
      return true;
    
  
  return false;


var skyColor = 'grey';
var name = 'ozbarry';
var n = 2;

var isHourBetween6And14 = isNumberBetween((new Date()).getHours(), 6, 14)
var isSkyGrey = skyColor === 'grey';
var isNameValid = isValueOneOf(name, ['ozbarry', 'web-dev']);
var isN2Or999 = isValueOneOf(n, [2, 999])

var canDoThing = isHourBetween6And14 && isSkyGrey && isNameValie && isN2Or999;

if (canDoThing) 
  // Do a thing here

这是一种完全自以为是的做事方式,大多数人不喜欢他们的代码在重构后变得更大,但拥有可维护的代码比更小的代码更好。

【讨论】:

【参考方案3】:
if(
    (condition 1) &&
    (condition 2 ==  condition 3) &&
    (false && (condition 6 == condition 7)
        || ((condition 8 && condition 9) && (condition 10 == condition 11)))
  )

如果 "condtion4 && condition 5" 评估为假,则该语句为假。当面对如此复杂的“if”条件时,正确使用间距和缩进将有助于提高可读性。您也可以尝试将其分解为更小的条件语句,从而产生布尔结果。

【讨论】:

【参考方案4】:

尝试将每个条件重写为函数以使其更具可读性。尝试以使它们有意义的方式命名函数(尝试检查的条件是什么)

例如

function satisfiesXYZCondition = function ()
   (condition 4 && condition  5) && (condition 6 == condition 7)

理想情况下,您应该将 if 语句中的所有条件替换为一个描述您正在检查的内容的函数。

【讨论】:

以上是关于如何评估带有大量 && 和 || 的 If 语句状况的主要内容,如果未能解决你的问题,请参考以下文章

如何避免短路评估

如何使用逻辑运算符评估前缀表达式

如何在 freemarker 中评估 if 语句?

如何评估 IDebugProperty2 的参考?

如何评估服务器基础性能 - CPU负载使用率内存&磁盘使用率网络带宽......

如何评估服务器基础性能 - CPU负载使用率内存&磁盘使用率网络带宽......