Thrasher
Thrasher

Reputation: 85

JavaScript conditional statement with check for empty returns string

In JavaScript you can check whether a variable has any value like this

if (strValue) {
    //do something
}

Today I encountered something beyond my understanding, a conditional where I used this wasn't working as I expected. I had some JavaScript code that looked similar to below snippet.

var blnX = false;
var intX = 3;
var strX = "2021-03-25T13:53:13.259352Z";

function test(blnValue, intValue, strValue) {
    return !blnValue && (intValue == 2 || ((intValue == 3 || intValue == 4) && strValue));
}

var result = test(blnX, intX, strX);

At this point I expected result to be true but it contained "2021-03-25T13:53:13.259352Z".

When I change the return statement like below,

return (((intValue == 3 || intValue == 4) && strValue) || intValue == 2) && !blnValue;

or like this,

return !blnValue && (intValue == 2 || (strValue && (intValue == 3 || intValue == 4)));

then it does return true.

To make it even more confusing when I change the function from the above snippet like below, then it does work like expected.

function test(blnValue, intValue, strValue) {
    if (!blnValue && (intValue == 2 || ((intValue == 3 || intValue == 4) && strValue)))
        return true;
    return false;
}

Can someone explain to me why the conditional from the return statement used in the first function is not returning the expected boolean value?

Upvotes: 0

Views: 641

Answers (4)

secan
secan

Reputation: 2669

Maybe it might help to consider, step by step, how return !blnValue && (intValue == 2 || ((intValue == 3 || intValue == 4) && strValue)); is evaluated:

/*
 * GIVEN:
 *   blnValue = blnX = false;
 *   intValue = intX = 3;
 *   strValue = strX = "2021-03-25T13:53:13.259352Z";
 */

/*0*/ !blnValue && (intValue == 2 || ((intValue == 3 || intValue == 4) && strValue));
/*1*/ !false && (3 == 2 || (( 3 == 3 || 3 == 4) && '2021-03-25T13:53:13.259352Z'));
/*2*/ true && (false || ((true || false) && '2021-03-25T13:53:13.259352Z'));
/*3*/ true && (false || (true && '2021-03-25T13:53:13.259352Z'));
/*4*/ true && (false || '2021-03-25T13:53:13.259352Z');
/*5*/ true && '2021-03-25T13:53:13.259352Z';
/*6*/ '2021-03-25T13:53:13.259352Z';

Also notice that:

const a = true && '2021-03-25T13:53:13.259352Z';
const b = '2021-03-25T13:53:13.259352Z' && true;
console.log(a);  // -> '2021-03-25T13:53:13.259352Z'
console.log(b);  // -> true

Upvotes: 0

Always Learning
Always Learning

Reputation: 5581

Expressions don't always return true or false in Javascript. They return the value of the last thing that they evaluated.

An easy trick to convert anything to true or false is to use a double-exclamation. One exclamation will give the opposite of the truthfulness of the expression, so two will switch it back to its original boolean equivalent.

See the sample code.

const a = 'hello'
const b = 1
console.log(b && a)
// outputs 'hello' since 'a' was the last evaluated thing
console.log(b || a)
// outputs 1 since 'b' was truthy and no need to evaluate a
console.log(!!(b || a))
// outputs true since !! quickly converts to boolean

Upvotes: 0

sjahan
sjahan

Reputation: 5940

You just have to understand how || or && work.

2 && 3 will return 3, because if the left operand is truthy, the right operand is returned. That's all.

It works in a if because 3 is truthy, so

if(2 && 3) {
    console.log("bip"); // will be displayed.
}

Truthy/falsy and boolean values are two different things.

Some reading:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR

https://developer.mozilla.org/en-US/docs/Glossary/Falsy

https://developer.mozilla.org/en-US/docs/Glossary/Truthy

Upvotes: 2

dkuznietsov
dkuznietsov

Reputation: 298

|| is in fact coalescing operator, not logical OR. It returns first non-falsey value of its operands, or last value otherwise

Upvotes: 0

Related Questions