&& / || operator strangeness in JavaScript - javascript

So, I was working on a project of mine, when I came across a problem like this:
var one = 1;
var two = 2;
var three = 7;
if (one === 1 || two === 2 && three === 3) {
console.log("ok"); // prints out ok
}
I'm pretty confused with this since I don't think it should print out "ok". I thought that since the condition after the && operator was false, it shouldn't run, but I'm evidently wrong. Can anyone clarify why it's working?

In Javascript, operators are not just evaluated left-to-right, certain operators have more precedence than others. Those with higher precedence (in this case, the && operator of precedence 13) will be evaluated before others (||, precedence 14).
For your particular case, you need to group your conditionals in order to achieve the functionality you want:
if ((one === 1 || two === 2) && three === 3) {
console.log("ok"); // prints out ok
}
JSFiddle

Related

"Do nothings" as statment in Javascript Condition

I want a ternary operator in JavaScript to return nothing if the statment is false
I have tried this:
1 == 1 ? alert('YES') : '';
But I want to know if this is the right way to make a statments "DO NOTHING" depending on the condition.
No, use if.
if (1 == 1) {
alert('YES');
}
Don't abuse the conditional operator as a replacement for if/else - it's confusing to read. I'd also recommend always using === instead of ==.
If you really want to do it, && will be one way.
1 == 1 && alert('ALERTED');
1 == 2 && alert('NOT ALERTED');
It is single statement.
A condition after an AND operator is only run if the first is true. So it is like an if statement.
did you try a single line if statement without brackets?
if(1 == 1) alert('Yes');

Can you have multiple and operators in JavaScript?

I have the following code:
if ((showHideDropdown.target.id !== "gear-icon") && (showHideDropdown.target.id !== "gear-image") && (showHideDropdown.target.id !== "settings") && (showHideDropdown.target.id !== "profile-icon") && (showHideDropdown.target.id !== "profile-image")){
I always thought that multiple and operators can be used like this, but nothing after the first two target id's worked. Maybe this has nothing to do with the operators, which is why I am asking if you can have multiple operators in a line. I'm a beginner in js so I haven't met this kind of problem before.
You can have multiple && conditions, but you'd probably be better off simplifying your check since your conditions seem to have lots of repetition of the same field. For instance:
const id = showHideDropdown.target.id;
const list = [`gear-icon`, `gear-image`, `settings`, `profile-icon`, `profile-image`];
if (!list.includes(id)) {
//...
}

Best way to refactor complex if expression [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I have just come on board to a big e-commerce project that has an angularJS front-end. I have been tasked with adding a lot of complex features to the checkout pages... which already have a lot of complex logic.
To make things harder I keep coming across lots of if statement expressions like the one below which are making it hard to understand and it is a slow process going through this code with many of these type of if expressions.
Some of these expressions are pretty critical and are sometimes even longer... There are no unit tests and when I ask other devs what this is checking for and why (just to be sure I understand) I usually get pointed to someone else rather than an explanation.
if ((!previousBillingAddress) || (previousBillingAddress && previousBillingAddress.id !== bag.paymentAddress.id)){
console.log('all of the above was true'); // just a dummy log
} else {
console.log('all of the above was false'); // just a dummy log
}
Does anyone have a good tip for refactoring these types of expressions?
I thought of breaking them down into functions that have descriptive names and the functions could return true or false but Im not sure if there is a better way.
Let there be
A = previousBillingAddress
B = previousBillingAddress.id !== bag.paymentAddress.id
then your expression is:
if (!A || (A && B)) {
log1
} else {
log2
}
What we can do we with !A || (A && B)? It's equal to !A || B:
A | B | !A | A && B | !A || (A && B) | !A || B
==========================================================
1 | 1 | 0 | 1 | 1 | 1
1 | 0 | 0 | 0 | 0 | 0
0 | 1 | 1 | 0 | 1 | 1
0 | 0 | 1 | 0 | 1 | 1
That's why your expression is equal to:
if (!previousBillingAddress || previousBillingAddress.id !== bag.paymentAddress.id) {
console.log('all of the above was true'); // just a dummy log
} else {
console.log('all of the above was false'); // just a dummy log
}
TL;DR
Above table is only check if !A || (A && B) is equal to !A || B. How to guess !A || B? In case of such expressions it's good to play with following rules:
A == !(!(A)) (rule 1)
!(A && B) == !A || !B (rule 2)
!(A || B) == !A && !B (rule 3)
A && (B || C) == A && B || A && C (rule 4)
So we have !A || (A && B), let's play. Due to rule 1 it's equal to
!(!(!A || (A && B)))
Now we use rule 3:
!(!(!A || (A && B))) == !(A && !( A && B))
Rule 2:
!(A && !( A && B)) == !(A && (!A || !B)) (*)
Due to rule 4:
A && (!A || !B) == (A && !A) || (A && !B)
We have (A && !A) || (A && !B) and it can be reduce to (A && !B). Now we can back to (*) and we have:
!(A && (!A || !B)) == !((A && !A) || (A && !B)) == !(A && !B)
With rule 2 we got:
!(A && !B) == !A || B
You can drop the previousBillingAddress && part - in the second operand of the || you already have estblished that previousBillingAddress is not falsy. That would make the overall condition
if (!previousBillingAddress || previousBillingAddress.id !== bag.paymentAddress.id) {
console.log('all of the above was true'); // just a dummy log
} else {
console.log('all of the above was false'); // just a dummy log
}
which seems short enough for me. If not, make an appropriately named helper function to which you pass the previousBillingAddress and the bag.
In my personal opinion, i think you can refactor and encapsulate the validation/check inside of a function, then if the same validation applies to other part of your code (file/module/etc..), you can reuse it. In this case you are using angular, so might be good to use an angular custom service for this type of business validations, since they also can manipulate the scope
Comments are our best friend. You want to make sure that the next person to take a look at your code knows exactly what it is supposed to do and from that, it will be quicker and easier to see exactly what it is doing.
In this case the expression in the if statement can be shortened. This is how I would comment it with almost a pseudocode approach:
// we need to check if the user has, and is using, a previous billing address
if (previousBillingAddress && previousBillingAddress.id === bag.paymentAddress.id)){
// the user is using a previous billing address
// do some work with the previous billing address
} else {
// the user is using a new address
// do some work with the new address
// save the new billing address
}
Note that previousBillingAddress is the main subject of this if statement. If we are checking for previousBillingAddress then in our first block we want to make sure we deal with what happens if we have a previous billing address. It's more logical that way.
It makes a lot less sense to check if we don't have a previous billing address and then what do we do if we have one.
Look how clean and logical it is! <3
I recommend hoisting the complex conditionals into Boolean variables (or constants, if your supported level of JS allows you to use const). For example:
var weakPrevBillingAddress =
!previousBillingAddress ||
(previousBillingAddress &&
(previousBillingAddress.id !== bag.paymentAddress.id));
if (weakPrevBillingAddress) {
console.log('judged weak previousBillingAddress');
// other processing expected here
} else {
console.log('judged strong previousBillingAddress');
// other processing expected here
}
As you and philip yoo suggest, you could hoist the conditional into a Boolean helper function. But most of the ways of defining such functions will put the logic farther away from the point of use, making comprehension harder. Boolean variables (a.k.a. "predicates") can be easily defined close to their use (e.g. right before your if statement). So there isn't much additional distance, but they still separate the computation of the Boolean value from its use. Your ability to focus on the computation separately can make things simpler and more comprehensible. As shown above, it also allows you to split long
lines and use indentation for better clarity.
I don't know if you have the flexibility to rename existing variable names. If you do, the ones you're using are exceedingly long. Long names can help increase understanding, but a 22-character name repeated several times per line is distracting, not clarifying. Shorter names, either for the source values, or just for the predicates you compute, can help. E.g.:
var weakPrevBA = !prevBA ||
(prevBA.id !== bag.paymentAddress.id);
Choosing good variable names is an art, and developer tastes about "how much description is enough" vary. But in an app that deals with billing addresses all the time, line after line after line, spelling out billingAddress every time doesn't necessarily help. If you're reading the code and comments, you probably are highly aware you're dealing with billing addresses. If not, add a quick comment, rather than spell out the full concept multiple times per line.
Note that I've also simplified the Boolean expression in this shorter example. (This was also suggested by Bergi) That can be a good idea--as long you're sure it can be simplified correctly. However, do this only with great caution. You don't have unit tests, so you have no easy way to test if simplifications are truly identical. And you're dealing with complex code. I recommend keeping the original Boolean expressions, at least to start (possibly with shortened names). That reduces one place bugs can creep in, at least until you understand the code more fully. The better you understand the code, and the simpler you have made it (e.g. by adding computed predicates, rather than long, complex expressions inside conditionals), the more freedom and safety you have in rewriting expressions.
Something like this
var billingId = previousBillingAddress && previousBillingAddress.id;
if (billingId || billingId === bag.paymentAddress.id){
console.log('all of the above was false'); // just a dummy log
} else {
console.log('all of the above was true'); // just a dummy log
}
what i did
since you are using if and else its not a good practice to use negation in the if statement. so i removed that
if you only want the negated part (without an else)
if (!(billingId || billingId === bag.paymentAddress.id)){
console.log('all of the above was true'); // just a dummy log
}
the && will return the first false, or the last true value. so billingId will equal false or the id. building upon that, your first if is checking if its "falsey" continue, so you can use the same variable as well.

More compact "if...else if" when executing same code

I have a JavaScript calls structured this way:
if (($(this).scrollTop() == 0) && !controlsVisibility) {
triggerControls();
}
else if (currentScroll > (previousScroll + 100) && controlsVisibility) {
triggerControls();
};
While triggerControls() does just-in-case typecheck for undefined, and uses controlsVisibility as default arg determine what exactly it is supposed to do. I think:
Did I made a mistake of not passing controlsVisibility as a function arg inside if clause. If value of that variable changes between I call triggerControls() and function's execution (microsecond?) — should I:
account for the possible change by using the global state (as it is now)
or
interfere the change by passing stable args in advance?
I understand that this might be determined on case-by-case basis, but I would really appreciate some tips.
If the current implementation (1) is OK
I could've written both scenario checks in one if just by using || as I am executing the same function. Except for being messy and making the code largely unreadable why shouldn't I do just that?
If value of that variable changes between I call triggerControls() and function's execution (microsecond?)
No. While your script is executing, nothing else will change that variable - JavaScript is single-threaded. Unless triggerControls does something asynchronous and expects the value to be the same in a future turn of the event loop, everything is fine.
I could've written both scenario checks in one if just by using || as I am executing the same function. Except for being messy and making the code largely unreadable why shouldn't I do just that?
I don't see a reason not to do that. It's not messy to avoid repetition (but dry), and I wouln't consider it unreadable. You even might use the ternary operator to shorten (and optimise) it:
if (controlsVisibility
? currentScroll > (previousScroll + 100)
: $(this).scrollTop() == 0
) {
triggerControls();
}
I disagree with the statement that rolling the two conditions with an || operator is unreadable. With the right formatting it is very readable:
if (
(($(this).scrollTop() == 0) && !controlsVisibility) ||
(currentScroll > (previousScroll + 100) && controlsVisibility)
) {
triggerControls();
};
That's clearly two conditions switched by controlsVisibility. I personally would prefer controlsVisibility to be checked first to make the fact that it's a switch clearer:
if (
(controlsVisibility && currentScroll > (previousScroll + 100)) ||
(!controlsVisibility && ($(this).scrollTop() == 0))
) {
triggerControls();
};
However, you also asked if there is a more compact way to write this and there is:
if (controlsVisibility ?
currentScroll > (previousScroll + 100) :
$(this).scrollTop() == 0
) {
triggerControls();
};
I'd argue that the code above is obvious and readable but not everybody likes the ternary operator.

Is it possible to automatically detect redundant conditional statements?

In JavaScript, is it possible to automatically detect redundant if-statements so that they can be written more concisely? I want to automatically detect redundant if-statements in the code that I've written, but I'm not sure how feasible it would be to detect redundant if-statements automatically, or whether there are existing source code optimizers for this purpose.
var x = prompt("Enter a number:");
if(x == 5 || x == 10){
}
if(x==5){
console.log("This if-statement is redundant!");
}
if(x == 5){
console.log("This if-statement is redundant! Is there any way to merge redundant if-statements like this one?")
}
if(x==10){
console.log("x is 10.")
}
I tried to remove the redundant if-statements using Google's Closure Compiler (using the advanced optimization setting), but the redundant if-statements still were not eliminated:
var a = prompt("Enter a number:");
5 == a && console.log("This if-statement is redundant!");
5 == a && console.log("This if-statement is redundant! Is there any way to merge redundant if-statements like this one?");
10 == a && console.log("x is 10.");

Categories

Resources