javascript if condition with multiple ifs - javascript

I'm running a UI component on every page and on one of the pages, there's an extra functionality linked to it. The UI component has a boolean called MyValue and the extra functionality has an object called ExtraObject and one of its properties is a boolean called ExtraBool.
I want to test if MyValue is true AND if ExtraObject.ExtraBool is false, BUT ONLY if ExtraObject exists. That way, if I'm on the pages that don't have ExtraObject, there's no error.
I tried this:
if (MyValue === true &&
(typeof ExtraObject === undefined || ExtraObject.ExtraBool === false)) {...}
How should I rewrite this?
At the moment, I keep getting "ExtraObject is not defined error".
Thanks.

That should be:
typeof ExtraObject === "undefined"
typeof returns the type of the expression as a string, so you need to compare the name "undefined" to the result.
In my opinion, your condition is a bit too explicit. I'd go with something shorter:
if (MyValue && !(ExtraObject && ExtraObject.ExtraBool)) {...}
If you're communicating with your own GUI code, you can assume that the types are as expected. Type checking in JavaScript is rather cumbersome, so if you know what you're dealing with you can be less explicit. (This doesn't apply to user input though. Never trust user input.)

The logic is not quite correct:
if (MyValue && ExtraObject && !ExtraObject.ExtraBool) { ... }
I'm guessing that null would be a value ExtraObject shouldn't have either; that is, I presume that you r condition is really better stated that it should be a reference to an object.
Thus, the condition as I wrote it will be true when MyValue is "truthy", ExtraObject is a reference to a real object, and the property ExtraBool on that object is "falsy".
Sometimes it's necessary to make explicit comparisons to boolean constants, but in my opinion it's a code smell. (Of course, it can also be dangerous to just check truthiness/falsiness ...)
edit If your requirement is that the expression be true when MyValue is true and either ExtraObject is not a reference to an object or it's ExtraBool property is true, then I'd write that:
if (MyValue && (!ExtraObject || !ExtraObject.ExtraBool)) { ... }
Which is "better" is a matter of personal preference and experience.

Truth table time!
A is MyValue*
B is window.ExtraObject**
C is ExtraObject.ExtraBool
A B C | O
------+--
0 0 0 | 0
0 0 1 | 0
0 1 0 | n/a***
0 1 1 | 0
1 0 0 | 1
1 0 1 | n/a***
1 1 0 | 1
1 1 1 | 0
What we find with these values is that the simplest equation to produce O is:
A && !C
So your code should be:
if (MyValue && !ExtraObject.ExtraBool) {}
But of course, you mentioned not wanting to run into issues if ExtraObject wasn't defined:
var extraBool = window.ExtraObject ? ExtraObject.ExtraBool : false;
if (MyValue && !extraBool) {}
An alternative means of writing extraBool is:
var extraBool = window.ExtraObject && ExtraObject.ExtraBool;
You can then inline this:
if (MyValue && !(window.ExtraObject && ExtraObject.ExtraBool)) {}
An alternative of writing !(a && b) is !a || !b, which means that:
if (MyValue && (!window.ExtraObject || !ExtraObject.ExtraBool)) {}
is also correct.
* it could be MyValue===true depending on how strict you need to be
** alternatively typeof ExtraObject !== 'undefined'
*** it's not actually possible to have ExtraObject be undefined and access ExtraObject.ExtraBool

if ((MyValue === true) && (typeof ExtraObject === undefined || ExtraObject.ExtraBool === false)) {}

Related

Why does Typescript flag a possible undefined value on array length check with greater than but not equals?

Given this snippet of a React component:
const AccountInformation = (props: { readonly accountData: AccountData | undefined | null }) => {
const hasMultipleAccounts: boolean = props.accountData?.customerAccounts?.length === 1 ? false : true
...
Why does Typescript complain that props.accountData?.customerAccounts?.length is possibly undefined when I check if it is greater than 0 (> 0) but the error goes away when I check if it is equal to 1 (=== 1)?
Is this a case where JS is doing something weird with an undefined property being interpreted as 0?
Writing it this way eliminates the error, but I'm trying to understand the behavior.
const hasMultipleAccounts: boolean = props.accountData?.customerAccounts?.length ?? 0 > 1 ? : true : false
More simply, you're asking why TypeScript complains about the second of these statements:
console.log(undefined === 1); // false
console.log(undefined > 0);
// ^−−−− Object is possibly 'undefined'.(2532)
...because any property access operation with optional chaining in it has undefined as one of its possible result values.
=== is more general than > is. === is used to see if the type of value of the operands match. But > is used to either compare two numbers or to compare two strings for relative "greater"-ness. TypeScript also prevents mixing those two:
console.log("1" > 0);
// ^−−− Operator '>' cannot be applied to types 'string' and 'number'.(2365)
console.log(1 > "0"");
// ^−−− Operator '>' cannot be applied to types 'number' and 'string'.(2365)
In JavaScript, we're (fairly) used to implicit conversion in these situations, but TypeScript's job is to apply strict typing, and so implicit conversion is generally not allowed. In JavaScript, undefined > 0 becomes NaN > 0 which is false (as is undefined <= 0). But TypeScript sees that as the error it likely is, and flags it up for you.
(Playground link for all of the above.)
If you want to use length > 0 you'll need null coalescing:
const i: number | undefined = undefined;
if (i ?? 0 > 0) {
}

JavaScript && Operator used for returns

I am working understanding a JavaScript library and I came across this statement:
const assetsManifest = process.env.webpackAssets && JSON.parse(process.env.webpackAssets)
Then later on in the library, it uses the assetsMannifest like an object e.g.
assetsManifest['/vendor.js']
I thought the && operator was only used to return boolean values in logical checks. Can someone explain to me what is going on here?
Many thanks,
Clement
This operator doesn't always return true or false. It doesn't work like in some other programming languages. In JavaScript && operator returns the first value if it's falsy or the second one if not.
Examples:
null && 5 returns null because null is falsy.
"yeah yeah" && 0 returns 0 because every string is truthy.
Not so obvious :-)
Further reading:
Why don't logical operators (&& and ||) always return a boolean result?
&& returns first value converting to false or last value converting to true. It's because no need to calculate full logical condition with && if first value is falsy
console.log(55 && 66);
console.log(0 && 77);
console.log(88 && 0);
Also you can use && or || as if operator:
if (itsSunny) takeSunglasses();
equals to
itsSunny && takeSunglasses();
in that context it is checking if process.env.webpackAssets is a truthy value. If it is it will evaluate and return the next part. in this case JSON.parse(process.env.webpackAssets)
The logic is essentially
if (process.env.webpackAssets) {
return JSON.parse(process.env.webpackAssets)
}
else {
return process.env.webpackAssets // (null | undefined | 0 | '' | false)
}
Both && and || are evaluting there arguments in lazy mode and return the last value, after witch the result is known.
123 && (0 || '' && 78) || 7 && 8 || [] && {} || 90 || 77 && 13
###_^^ both results are possible 123 && ???
#_^^ first part is falsy, resume 0 || ??
#####_^^ can't be true, return ''
^^_########## 0 || '' return ''
^^_################ return ''
#######################_^^ resume
#_^^ resume
^^_# return 8
^^_###### return 8
^^_########################## drop
And the result is 8.

How to write shorter control statements in javascript

If i want to test two properties of one in javascript i have to write
((a test b ) && (a test c))
is there a way to write something like
(a test ( b && c))
for example
if(a === NaN || a === Infinity){…}
to
if (a === (NaN || Infinity)){…}
Just wondering if there were shorthands like this.
Sadly, no.
if (a === (NaN || Infinity)){…} would test a === Infinity. First it would check (NaN || Infinity) (evaluates to Infitity), the check.
Additionally, checking against NaN always returns false. Try it: NaN === NaN. Use isNaN(a) instead.
Yes, there is a shortcut:
if ([val1, val2, val3 /*...*/].indexOf(a) > -1){ /* ... */ }
or even shorter:
if (~[val1, val2, val3 /*...*/].indexOf(a)){ /* ... */ }
Note it won't work with NaN, because comparing to NaN is useless. Even NaN == NaN is false, that's why there are isNaN and Number.isNaN.

if(xxx || xxx), what am I doing wrong?

Can someone explain to me what am I doing wrong?
function navMenuIntervalCheck() {
if (currentSiteUrl != "subsites/players.php" || currentSiteUrl != "subsites/itemshop.php") {
$.ajax({
url: currentSiteUrl,
cache: false,
success: function (dataForContainer) {
$('#container').html(dataForContainer);
}
});
}
screenControlCheck();
};
setInterval(function () {
navMenuIntervalCheck()
}, 5000);
When I run my website it refreshes even when currentSiteUrl==subsites/players.php
As x!='a' || x!='b' is always true, I guess you wanted && instead of ||.
Read || as OR and && as AND.
More details in the MDN on logical operators.
currentSiteUrl can only have one value, so it will always be that at least one of the values you're testing will not equal currentSiteUrl, making the if condition always true.
I think you meant to use && or you meant to do == with ||.
Your code says this :
Refresh when currentSiteUrl is different than subsites/players.php or different than subsites/itemshop.php.
So subsites/players.php is indeed different than subsites/itemshop.php
Use && instead of ||
Look at your if statement:
if (a != foo || a != bar)
Lets look at the possibilities:
a = foo. This will evaluate as true, because a != bar
a = bar. This will evaluate as true, because a != foo
a = anything else. This will evaluate as true, because a != foo
Your if statement always evaluates to true.
As others have already said, you want to replace your || with &&.
Let me throw a logical rule at you, called DeMorgan's Law. It's really useful when learning how to set up a good if statement.
!(a || b) === !a && !b
also
!(a && b) === !a || !b
What that says is: "Not (one event or another)" is the same thing as "Not one event and not another", and "Not (one event and another)" is the same thing as "Not one event or not the other".
I know this has been answered but thought it might help to add some additional information using your own code.
As said, switching logical operator from || to && will work:
if (currentSiteUrl != "subsites/players.php" && currentSiteUrl != "subsites/itemshop.php")
But why is that?
Using ||
The || logical operator returns true if either the first or second expression is true and only if both are false will it return false.
Hence:
if currentSiteUrl != "subsites/players.php" is true you end up in the if block
if currentSiteUrl != "subsites/players.php" is false and currentSiteUrl != "subsites/itemshop.php" is true you end up in the if block
There will never be another scenario as your variable currentSiteUrl can only hold a single value and as such one of the expressions will always be true causing you to always end up in the if block.
Using &&
Using the && logical operator on the other hand though returns false if either the first or second expression is false and only if both are true will it return true.
Hence:
if currentSiteUrl != "subsites/players.php" is true and currentSiteUrl != "subsites/itemshop.php" is true you end up in the if block
if currentSiteUrl != "subsites/players.php" is true and currentSiteUrl != "subsites/itemshop.php" is false you don't end up in the if block
if currentSiteUrl != "subsites/players.php" is false you don't end up in the if block
There will never be another scenario, because only if both expression are true will you end up in the if block and as soon as either expression is false will you not.
How are you getting the currentSiteUrl. A url is followed by protocol:://domain
Try using the follwoing property to get URL and then match it
window.location.href
This url will also include the http or https and domain name

Why `null >= 0 && null <= 0` but not `null == 0`?

I had to write a routine that increments the value of a variable by 1 if its type is number and assigns 0 to the variable if not, where the variable is initially null or undefined.
The first implementation was v >= 0 ? v += 1 : v = 0 because I thought anything not a number would make an arithmetic expression false, but it was wrong since null >= 0 is evaluated to true. Then I learned null behaves like 0 and the following expressions are all evaluated to true.
null >= 0 && null <= 0
!(null < 0 || null > 0)
null + 1 === 1
1 / null === Infinity
Math.pow(42, null) === 1
Of course, null is not 0. null == 0 is evaluated to false. This makes the seemingly tautological expression (v >= 0 && v <= 0) === (v == 0) false.
Why is null like 0, although it is not actually 0?
Your real question seem to be:
Why:
null >= 0; // true
But:
null == 0; // false
What really happens is that the Greater-than-or-equal Operator (>=), performs type coercion (ToPrimitive), with a hint type of Number, actually all the relational operators have this behavior.
null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:
null == null; // true
null == undefined; // true
Value such as false, '', '0', and [] are subject to numeric type coercion, all of them coerce to zero.
You can see the inner details of this process in the The Abstract Equality Comparison Algorithm and The Abstract Relational Comparison Algorithm.
In Summary:
Relational Comparison: if both values are not type String, ToNumber is called on both. This is the same as adding a + in front, which for null coerces to 0.
Equality Comparison: only calls ToNumber on Strings, Numbers, and Booleans.
I'd like to extend the question to further improve visibility of the problem:
null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0; //false
null < 0; //false
It just makes no sense. Like human languages, these things need be learned by heart.
JavaScript has both strict and type–converting comparisons
null >= 0; is true
but
(null==0)||(null>0) is false
null <= 0; is true but (null==0)||(null<0) is false
"" >= 0 is also true
For relational abstract comparisons (<= , >=), the operands are first converted to primitives, then to the same type, before comparison.
typeof null returns "object"
When type is object javascript tries to stringify the object (i.e null)
the following steps are taken (ECMAScript 2015):
If PreferredType was not passed, let hint be "default".
Else if PreferredType is hint String, let hint be "string".
Else PreferredType is hint Number, let hint be "number".
Let exoticToPrim be GetMethod(input, ##toPrimitive).
ReturnIfAbrupt(exoticToPrim).
If exoticToPrim is not undefined, then
a) Let result be Call(exoticToPrim, input, «hint»).
b) ReturnIfAbrupt(result).
c) If Type(result) is not Object, return result.
d) Throw a TypeError exception.
If hint is "default", let hint be "number".
Return OrdinaryToPrimitive(input,hint).
The allowed values for hint are "default", "number", and "string". Date objects, are unique among built-in ECMAScript object in that they treat "default" as being equivalent to "string".
All other built-in ECMAScript objects treat "default" as being equivalent to "number". (ECMAScript 20.3.4.45)
So I think null converts to 0.
console.log( null > 0 ); // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true
Mathematically, that’s strange. The last result states that "null is greater than or equal to zero", so in one of the comparisons above it must be true, but they are both false.
The reason is that an equality check == and comparisons > < >= <= work differently. Comparisons convert null to a number, treating it as 0. That’s why (3) null >= 0 is true and (1) null > 0 is false.
On the other hand, the equality check == for undefined and null is defined such that, without any conversions, they equal each other and don’t equal anything else. That’s why (2) null == 0 is false.
I had the same problem !!.
Currently my only solution is to separate.
var a = null;
var b = undefined;
if (a===0||a>0){ } //return false !work!
if (b===0||b>0){ } //return false !work!
//but
if (a>=0){ } //return true !
It looks like the way to check x >= 0 is !(x < 0) In that way make sense the response.

Categories

Resources