FAQ: Conditional Statements - Logical Operators


#1

This community-built FAQ covers the “Logical Operators” exercise from the lesson “Conditional Statements”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Web Development

Introduction To JavaScript

FAQs on the exercise Logical Operators

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!


#2

How could I negate the value of the entire statement with ! as per additional experementing advice? It’s not like with the previous example where there is a boolean set in variable. So how can I use the bang operator on the two comparisons to negate them?


#3

we could simple use the bang operator at both conditions:

console.log( !false && !false );

or we can use the order of operations to our advantage:

console.log( !(false && false) );

parentheses are evaluated first, so the order is:

parentheses -> and operator -> bang operator


#4

It is not a bang operator in JavaScript, but in Ruby. In JS it is the NOT operator.

Any truthy expression in any form will be cast to a boolean and negated, so will yield, false. The opposite will happen when we negate a falsy expression and will yield, true.


#5

The exercise mentions we can add optional parentheses to the conditions to make it clearer for other developers. What is considered best practice? Is it recommended to use the optional parentheses or not? Thanks for the help!


#6

Brackets are for grouping, and if grouping is not required for operator precedence, we don’t need them. Code is just as readable without them, assuming the reader understands order of operations.


#7

Thank you! That is really helpful!


#8

I have a query about the different positioning options of the not operator ! in an if() conditional statement, and the requirement (or not) of brackets, depending on the desired outcome. For example:

// both conditions T: prints pass

let x = 'blue';
let y = 5;

if (x === 'blue' && y <= 5) {
    console.log('pass');
} else {
    console.log('fail');
}

If we wanted to negate the whole conditional statement, could the above code be modified using either of the following?

// both conditions T, but ! reverses to F: prints fail
if (!(x === 'blue' && y <= 5))

or

// both conditions T, but ! reverses to F: prints fail
if (!x === 'blue' && y <= 5)

i.e. I get the same result with or without the brackets, so am I right to assume that, here, precedence rules mean that the brackets are optional? However, would use of the brackets be preferrable due to readability?

If instead of negating the whole conditional statement, we wanted to negate both conditions separately before applying the logical operator, could the code in our original example be modified using either of the following?

Note: I’ve also made the following additional two changes to the example:
(i) mathematical operator <= (less than or equal to) changed to > (greater than); and
(ii) logical operator && (and) changed to || (or).

// 1st condition F, 2nd condition T: prints pass
if (!(x === 'blue') || !(y > 5)) 

or

// 1st condition F, 2nd condition T: prints pass
if (x === !'blue' || y > !5) 

Even though my own ‘trial and error’ testing has given me the outcomes above, I want to check that all of these syntax alternatives are both valid and good practice, as I’m aware that my limited testing may not paint the whole picture.


#9
a = true, b = true

In any configuration with AND, NOT will render as false.

! a && ! b    // <- false
! a && b      // <- false
a && ! b      // <- false
! (a && b)    // <- false

Different configurations with OR, not will render as false when applied to both operands, and true when applied to only one operand.

! a || ! b    // <- false
! (a || b)    // <- false

! a || b      // <- true
a || ! b      // <- true

Your last example is a bit off the beaten path. When we apply NOT directly to a non-boolean it first casts the value to a boolean, then negates it.

! 'blue'

'blue' is cast to true since a sting of any length but zero is truthy. NOT toggles it to false

However the logic is little fuzzy since the expression,

x === ! 'blue'

is akin to writing,

x === ! x

which is an oxymoron.

! 5

becomes false as well, since any number but 0 is truthy, and toggling that gives false.

Any number greater than zero is greater than false.

5 > false     // <- true
-5 > false    // <- false

This brings us to strict versus loose comparison.

0 === false    // <- false
0 == false     // <- true

Notice how the double = coerces the 0 to a boolean.

At any length, that last example is one to avoid owing to its mutation of objects before the comparison. That kind of logic could lead to some serious problems if it is not very thoroughly tesed and backed by sound reasoning.


#10

I’m still uncertain, as the original exercise in the lesson doesn’t use variables with boolean values (as you have with a = true and b = true). Instead it uses one variable with a string value, and another with a number value (as in my example x = 'blue' and y = 5. Am I right in understanding that the boolean values arise when these non-boolean values are ‘tested’ with comparison operators in the conditional statement? i.e.

… with both conditions, here, rendering the boolean true?

If this is the case, then could you confirm that what I have deduced as follows is correct for my example if( && ) statement (with mathematical comparisons)?

When the variables:
x = 'blue';
and
y = 5;

A)
if (!x === 'blue' && y <= 5)
and
if (!(x === 'blue' && y <= 5))
Both result in ‘false’ for the same reason, whether brackets or not are used.
First, the two comparisons render (true && true) = true
Then the ! negates this to give a final result of false.

B)
if (!x === 'blue' && y > 5)
and
if (!(x === 'blue' && y > 5))
Note <= has changed to >
First, both render (true && false) = false for the same reason, whether brackets or not are used.
Then the ! negates this to give a final result of true.

C)
if (!(x === 'blue') && !(y > 5))
Here brackets must be used if our intention is to negate each comparison separately before applying the && operator.
First, the two comparisons render (true && false)
Then the two ! negate both booleans separately to give (false && true), which gives a final result of false.

D)
if (!(x === 'red') && !(y > 5))
Note blue has changed to red
Again, brackets must be used if our intention is to negate each comparison separately before applying the && operator.
First, the two comparisons render (false && false)
Then the two ! negate both booleans separately to give (true && true), which gives a final result of true.

Finally…

I totally get that this is…

:joy::rofl::joy::rofl:

… and applies twisted logic that I wasn’t intending. So, let’s just forget about that one as something accidently stumbled-across while ‘playing around’ :wink:


#11

But they are both truthy, so not much difference.


#12

Think of outcome. Non-boolean values still have a potential to be truthy or falsy. Only a truthy value can make it into the first branch of an if statement. Their outcome evaluates to true but the value does not change. Control flow passes to the first branch and that code is executed.

When expression A is truthy and espression B is truthy, the outcome of ANDing in a conditional branch is to hand control flow to the first branch. There is no conversion of either operand. Only their truthiness is evaluated.

Draw out three truth tables

AND  T  F
  T  t  f
  F  f  f

 OR  T  F
  T  t  t
  F  t  f

NOT
  T  f
  F  t

TL; DR. Have to come back to this. Please bear with me.


#13

No problem… no urgency, just appreciate your attempt to ‘untangle’ my understanding.

I think I can see now that each of the ‘comparisons’ (e.g. y > 5 ) in my conditional statement example, even though based on non-boolean values, will evaluate to either true or false. Then, depending on which logical operators (&&, || or !) are also applied, an overall evaluation of truthiness will be arrived at for the conditional statement as a whole, of either:

true - executing the code block in the first branch (‘if’ branch); or
false - executing the code block in the second branch (‘else’ branch).

So, in my 4 examples (A, B, C and D), where I’ve said, for example:

what I actually mean, and therefore should have said, is:

First, the two comparisons evaluate to TRUE & TRUE = TRUE.
Then the ! negates this first evaluation of TRUE to give a final evaluation of FALSE, which executes the code block in the second branch (‘else’ branch).

I’d be grateful if you could still check whether my 4 examples are correct (in terms of ! position, use of brackets, and final outcome), bearing in mind this adjustment to the wording and therefore their interpretation.


#14

If x is 'blue', then ! x will be false since ‘blue’ is truthy. We would only NOT x if it was an expression other than a string literal. Instead, NOT the comparison expression, which will need brackets since Logical NOT has precedence to IDENTITY (Strict Equality).

! (x === 'blue')

is false when x is ‘blue’, true when x is not ‘blue’.

When brackets are used to group expressions, then what’s inside is evaluated first. When there are no brackets then we follow left to right associativity.

! x === 'blue'  =>
false === 'blue' ?  false

Not so. As we’ve shown they both result in false but not for the same reason.

! x

short-circuits AND so the second operand is not evaluated.

! (A && B)

is false because it negates the full evaluation of both truthy operands with AND.

In your example B, again, it is not the same reason. ! x is false when x is truthy. That short-circuits AND.

We say the F && F is false, but in truth, F && anything is false since anything never gets evaluated when the first operand is false.

In C, not truthy && not truthy short-circuits. We never get to the second operand. If expression A is truthy, we never look at expression B.

In D, both expressions will be falsy, so NOTting both will make them both true. We’ve already seen that,

! A && ! B

is the same as,

! (A && B)

#15

Found this table on MDN

Operator precedence


#16

Thanks so much for that analysis @mtf… I’ve managed to follow it through and I’m now clear about my examples A, B and D :smiley:

Can I just query your explanation of my example C?

:thinking: Shouldn’t this be:

  • (not truthy && truthy) short-circuits… as !(y > 5) is NOT(falsy) i.e. truthy?

  • But as you say we never get to the second operand anyway… but because the first expression is not truthy, because if it were truthy, then with an ( && ) statement we would have to evaluate the second operand to see if it were also truthy.

Is this correct?


#17

Correct.

Recall that ! A && ! B is the same as ! (A && B), in which case there would be no short-circuit. But when written as,

! A && ! B

it short-circuits when A is truthy. A must be falsy for ! B to be evaluated. If B is falsy then ! B is true, and the final resolution of the two is true.

Note that the outcome of A && B is literally, B when A is truthy.

6 && 7    // <-  7

How’s that for derailing the boolean train?

7 && 6    // <-  6

Go back and read that sentence again, just to cement the logic of it. We kind of need to go down this rabbit hole to really get a picture of what truthy and falsy are all about. It also reveals more insight into what AND and OR represent as operators.

Consider the following piece of code…

const maximize = (a, b) => a > b && a || b;

What do you suppose it is doing?


#18

Coach Hitchcock of the Edmonton Oilers…

“You don’t take your skill for granted, but you trust your work…”


#19

You’ve lost me in the second half of your post… I think derailing boolean trains is beyond my reach at the moment… maybe I’ll be ready to go down that rabbit hole in a few weeks time after some more basics (I only started with JavaScript on Saturday as a complete beginner) :wink:

Just to clarify, when you say…

…do you mean they both evaluate to an outcome of false, when…

A = true
and
B = true

because:

(!A && !B)
short-circuits at the first operand (!A) because this evaluates to NOT true
i.e. an outcome of false

and

(! (A && B))

  1. evaluates the (A) within the brackets to true, so doesn’t short-circuit, and next
  2. evaluates the (B) within the brackets to true
  3. which is then negated by the ! (outside the brackets) giving an outcome of false…?

I assume you aren’t referring to my example of:

because wouldn’t that mean…

if

A = x = 'blue'
and
B = y = 5

then

(!A && !B)
still short-circuits at the first operand (!A) because this evaluates to NOT true
i.e. an outcome of false

but

(! (A && B)) gives a different outcome…

  1. it does still evaluate the (A) within the brackets to true, so doesn’t short-circuit, but next
  2. evaluates the (B) within the brackets ( y > 5) to false (because B = y = 5)
  3. which is then negated by the ! (outside the brackets) giving an outcome of true …?

:crazy_face: :sweat_smile:


#20

Quick reply:

A and B in my pseudo code are expressions.

A = x === 'blue'
B = y > 5

In the above real code they still represent expressions. Lock in on that.

The = operator is right to left associative so reads from the right. 5 is assigned to y, and the reference is assigned to B.