0

I found some js code that looks something like this:

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

Will the following code evaluate as true or false if the expression (condition 4 && condition 5) evaluates as false? And why does it evaluate as true or false? Trying to get a good idea of how to read if statement with a mixture of && and || statements. I thought this was too may but if there is a way to refactor this code please let me know.

Cœur
  • 37,241
  • 25
  • 195
  • 267
web-dev
  • 133
  • 2
  • 11
  • it won't return true or false unless the vars are true or false... – dandavis Apr 08 '16 at 19:54
  • @dandavis this is untrue. In javascript, aside from literal values, every value also holds a truthiness. For instance, `if ("am I truthy") { alert("THE TRUTH!"); }` will execute the alert box. – OzBarry Apr 08 '16 at 20:17
  • 1
    @OzBarry: I meant that the OP's IF won't always be `false` just because 4/5 is `false`. a lot of folks think that `x=(0 && 1 || 0)` would be `false`, since the `0 && 1` would mentally read "not true", but that whole is actually "0 else 0", so the result is `0`; a datum result instead of a comparison result. as for the expression value inside the IF, both `false` and falseys (like `0`) will have the same effect... – dandavis Apr 08 '16 at 21:02
  • @dandavis oh, sorry, I misunderstood your original statement. – OzBarry Apr 08 '16 at 21:08

4 Answers4

2

Parentheses take top precedence && takes precedence over ||

See operator precedence in javascript on MDN and this SO question

If (condition 4 && condition 5) is false, the outcome will still be dependent on (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)
            ) 
    )
)

Can this be refactored: absolutely. How? Depends on the conditions and logic.

Community
  • 1
  • 1
Nivas
  • 18,126
  • 4
  • 62
  • 76
2

Personally, I break it out into variables.

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
}

A lot of people think that having fewer lines is a sign of good code, but it's definitely NOT. Readability and maintainability are far more meaningful to every developer who has to deal with any code.

Break out the conditions into very understandable variables (ie use variable names that describe the condition), and reduce it down into simpler things. You may find that breaking your full condition into smaller functions may also help.

So let's do another more meaningful boolean equation. Let's say we only want to execute a block of code if:

  • It is between 6am and 2pm
  • The value of skyColor is 'grey'
  • Your name is either 'ozbarry' or 'web-dev'
  • The value of n is either 2 or 999

Based on your current example, we'd start with something like:

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
}

This will do the right thing, but this will be a nightmare to maintain, and this is a pretty basic example. Let's do some refactoring!

First, let's pull some of these conditions into variables so we can track them better, and remove comments, since the variable names will reflect what we're testing:

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
}

This is better, but there is still some problems. Some conditions are still long or unclear from a code perspective. I'm mainly looking at isHourBetween6And14, but the last two could also use some attention, so let's split these out into meaningful functions:

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
}

Finally, a thing I like to do is join long conditions before the if statement. It will make your condition much more readable while future developers won't need to mentally do the logic each time to know whether it will execute the block:

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
}

This is a completely opinionated way to do things, and most people don't like their code getting larger after a refactor, but it is better to have maintainable code than smaller code.

OzBarry
  • 1,098
  • 1
  • 17
  • 44
0
if(
    (condition 1) &&
    (condition 2 ==  condition 3) &&
    (false && (condition 6 == condition 7)
        || ((condition 8 && condition 9) && (condition 10 == condition 11)))
  )

If "condtion4 && condition 5" evaluate to be false, the statement is false. When faced with such a complex "if" conditionals, proper use of spacing and indentation will help readability. Also you can try breaking it up into smaller conditional statements yielding Boolean results.

Art Solano
  • 99
  • 11
0

Try to re-write each conditional as a function to make it more readable. Try to name functions in a way that will make them meaningful (what is the conditional trying to check)

e.g.

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

Ideally you should replace all of the conditionals in the if statement with one function that describes what you're checking for.

NicolasMoise
  • 7,261
  • 10
  • 44
  • 65