How can I simplify `(variableA && !variableB) || !variableA` expression in JavaScript? - javascript

Please see this minimum example:
const result = (variableA && !variableB) || !variableA;
In this expression, I can't simply write this
const result = variableA && !variableB;
Because if variableA = 0, the result will be different
const variableA = 0;
const variableB = undefined;
console.log((variableA && !variableB) || !variableA); // true
console.log(variableA && !variableB); // 0
Is there any way I can simplify this expression?

(variableA && !variableB) || !variableA; if we use factoring to this result below
(!variableA || variableA) && (!variableA ||!variableB)
first part is always true then only second part is enough for u
!variableA ||!variableB
const variableA = 0;
const variableB = undefined;
console.log((variableA && !variableB) || !variableA); // true
console.log(!variableA ||!variableB);

You could use
!(a && b)
or the equivalent with De Morgan's laws
!a || !b
const
f = (a, b) => (a && !b) || !a,
g = (a, b) => !(a && b),
h = (a, b) => !a || !b
console.log(0, 0, f(0, 0), g(0, 0), h(0, 0));
console.log(0, 1, f(0, 1), g(0, 1), h(0, 1));
console.log(1, 0, f(1, 0), g(1, 0), h(1, 0));
console.log(1, 1, f(1, 1), g(1, 1), h(1, 1));

Your answer #nina-scholz is not (explicit) aware of the javascript type-casting. Your own acepted answer will only work in your special usecase while using the ! (not) operator.
const variableA = 0;
const variableB = undefined;
console.log(variableA && variableB); // 0
console.log(variableA || variableB); // undefind
This will neither have a boolean result because even using the boolean operators && and || the resulting type is not boolean.
You need to typecast the variables to boolean before logical operation.
The ! (not) operator will do this explicit. If you double it !! you have surely a boolean value to logical compare. This works also for undefined values.
const variableA = 0;
const variableB = undefined;
console.log(!!variableA && !!variableB); // false
console.log(!!variableA || !!variableB); // false
Now your result of the logical operation is always from a logical boolean expression.
Check your question again:
const variableA = 0;
const variableB = undefined;
console.log("no booleans -----");
console.log(variableA); // => 0 - what is NOT a boolean
console.log(variableB); // => undefined - what is NOT a boolean
console.log("explicit booleans with not operator -----");
console.log(!variableA); // => true - now it is a boolean
console.log(!variableB); // => true - now it is a boolean
console.log("explicit booleans with double not operator -----");
console.log(!!variableA); // => false - now it is a boolean
console.log(!!variableB); // => false - now it is a boolean
console.log("with and without typecast -----");
console.log(variableA && !variableB); // => 0 - what is NOT a boolean
console.log(!!variableA && !variableB); // => false - now all are boolean
console.log("your question with and without explicit typecast -----");
console.log(0 || !variableA); // => true
console.log(false || !variableA); // => true
console.log(0 || true); // => true
console.log(false || true); // => true
As #pc-coder has already shown, you may change your current expression
const variableA = 0;
const variableB = undefined;
console.log((variableA && !variableB) || !variableA);
// expand expression
console.log((variableA || !variableA) && (!variableB || !variableA));
// reduce expression while first part (variableA || !variableA) is always true
console.log(!variableB || !variableA);
// the above will work thru automatic typecast with not operator
// or exclude the not operator and typecast explicit
console.log(!(!!variableB && !!variableA));

Related

Is it ok to use javascript `??` operator as shorthand

I normally use ternary operators like:
let foo = str.match(/[*]/g) ? str.match(/[*]/g) : "none!";
Since using PHP, I've noticed the language has a lot of shorthand and for ternary operators, would use:
$foo = $view->test ?? "none";
I have not seen that in javascript (or documentation on it) but tried it like:
let str = "1234";
let foo1 = str.match(/[*]/g) ?? "none;
console.log(foo) // "none"
let str1 = "1*2*";
let foo1 = str1.match(/[*]/g) ?? "none;
console.log(foo1) // ['*','*']
and it seemingly works. Is this an acceptable way of using ternary operators when checking against the existence of an element?
I guess it's totally legit to use the nullish coalescing operator or ??.
See https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator for examples and some documentation on it.
Make sure to check browser compatibility though !
=======
There is also the logical OR || operator which can be used for similiar operations:
o1 = true || true // t || t returns true
o2 = false || true // f || t returns true
o3 = true || false // t || f returns true
o4 = false || (3 == 4) // f || f returns false
o5 = 'Cat' || 'Dog' // t || t returns "Cat"
o6 = false || 'Cat' // f || t returns "Cat"
o7 = 'Cat' || false // t || f returns "Cat"
o8 = '' || false // f || f returns false
o9 = false || '' // f || f returns ""
o10 = false || varObject // f || object returns varObject
Check out : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators for reference

That Operator || in console.log() works like || operator?

How it's work for example;
let x;
console.log(x || 2); // 2
if
let x = 4;
console.log(x || 2); // 4
if
let x = 5;
let y = 7;
console.log( y || x || 2);
it's mean that console.log() write first value that is true ?
What you're seeing isn't related to console.log. It's called short circuiting.
When comparing values with ||, it will always return the first truthy value. If no truthy values are present, it will return the last value being compared.
let a = false || true;
let b = false || null || 'b';
let c = undefined || !a || 10;
let d = undefined || false || null; // no truthy values
console.log(a); // true
console.log(b); // 'b'
console.log(c); // 10
console.log(d); // null
let x = 5;
let y = 7;
console.log( y || x || 2); //return 7
expr1 || expr2 Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true.
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators

What's the difference between a ternary operation and this alternative?

I'd like to know why the following two expressions return the same result i.e. when val_bool is always a boolean [true or false]:
('oninput' in document.documentElement && !val_bool) && 'first result' || 'second result';
and
('oninput' in document.documentElement && !val_bool) ? 'first result' : 'second result';
If you open the console and run the following:
var val_bool = true;
('oninput' in document.documentElement && !val_bool) && 'first result' || 'second result';
second result is output. The same result is output when I make a change to ternary:
var val_bool = true;
('oninput' in document.documentElement && !val_bool) ? 'first result' : 'second result';
I'm not familiar with the mechanism with which the first logical expression resolves its result.
In ternary expression x ? y : z the first part is evaluated as boolean and the appropriate value returns.
In another line of code x && y || z things are different: it's basically 2 expressions instead of 1.
This link is useful here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
We can see, that && and || have left-to-rigth associativity, which means the left part is evaluated first. The following lines are equal:
x && y || z
(x && y) || z
Expression x && y is evaluated first, and x && y || z becomes result(x,y) || z.
Example when results differ while inputs are the same:
const logical = (x, y, z) => x && y || z;
const ternary = (x, y, z) => x ? y : z;
console.log(
logical(1, 0, 1) // 1 && 0 || 1 => 0 || 1 => __ 1 __
)
console.log(
ternary(1, 0, 1) // if (1) then 0; otherwise 1 => __ 0 __ (Boolean(1) === true)
)
Just posting this for posterity.
I found a gem of a quote on an article on Logical Operators. Somewhere under Operators || and &&, one paragraph reads:
The result of a || or && expression is always the underlying value of
one of the operands, not the (possibly coerced) result of the test.
It turns out I've been looking at things from the point of view of the evaluation, as opposed to the underlying value.
So my initial question had the following expression:
('oninput' in document.documentElement && !val_bool) && 'first result' || 'second result';
Let's replace the operands with simple variables:
var a = true;
var b = true;
var c = 'first result';
var d = 'second result';
(a && !b) && c || d;
Firstly, (a && !b) will evaluate to false, because a is true and !b is false and true && false is false.
Secondly, that false result will evaluate with c ((false) && c). Again, we end up with false because c will evaluate to a string (true), and false && true is false.
Finally, the result of false will evaluate with d, only this time the operator is || and the evaluation of false || true is true. However, it's not the evaluation that will be returned, but the underlying value, which is second result.
Of course, things will change when I update the original value of b from true to false. Everything to the left of || evaluates to true, so when you evaluate true || true you get true, but which true is the question. It's the true on the left of ||, because if we evaluated 'a' || 'b', the result would be 'a'.
All tolled, it's not equivalent to the ternary operator in function, but the results for the two specific expression [if the variable types remain the same] should be the identical.

Multiple conditions in if statement on both sides of the logical operator

I was experimenting with having multiple arguments in an if statement on both sides of the logical operator. I first started with the || operator, which worked as expected:
var a = 'apple', b = 'banana', c = 'cherry';
if (a == 'banana' || a == 'apple' || b == 'banana' || b == 'apple') {
console.log('example 1') // returns
}
if ((a || b) == 'banana' || (a || b) == 'apple') {
console.log('example 2') // returns
}
if (a == ('apple' || 'banana') || b == ('apple' || 'banana')) {
console.log('example 3') // returns
}
if ((a || b) == ('apple' || 'banana')) {
console.log('example 4') // returns
}
So far, no unexpected results.
However, when following a similar structure when replacing the || operator for the && operator, things don't quite work as I expect them to.
if ((a == 'banana' && b == 'apple') || (a == 'apple' && b == 'banana')) {
console.log('example 5') // returns
}
if (((a || b) == 'banana') && ((a || b) == 'apple')) {
console.log('example 6') // DOESN'T RETURN
}
if ((a || b) == 'banana') {
console.log('example 6a') // DOESN'T RETURN - consistent with example 6
}
if ((a == ('apple' || 'banana')) && (b == ('apple' || 'banana'))) {
console.log('example 7') // DOESN'T RETURN
}
if (a == ('apple' || 'banana')) {
console.log('example 7a') // returns - inconsistent with example 7
}
if (b == ('apple' || 'banana')) {
console.log('example 7b') // DOESN'T RETURN - inconsistent with example 7a
}
if ((a && b) == ('apple' || 'banana')) {
console.log('example 8') // DOESN'T RETURN
}
if ('apple' == (a || b) && 'banana' == (a || b)) {
console.log('example 9') // DOESN'T RETURN
}
Now, I am wondering: is there a flaw in my logic or can it just not be done this way? My aim is to write these if statements as short as possible, for the purpose of readibility and maintainability. Clearly I am just exploring possibilities.
Does anyone know any way to go about this? Especially example 7/7a/7b seems peculiar to me because it yields inconsistent results despite a similar structure [Fiddle]
The Logical OR operator doesn't work in a way you're looking for.
Returns expr1 if it can be converted to true; otherwise, returns expr2. Thus, when used with Boolean values, || returns true if either operand is true; if both are false, returns false.
MDN
One alternative way could be make use of array's indexOf method. Just be aware it will return the index of the array element, so 0 could be a valid value also. In order to make our if statement works as expected, we have to use 0 <= ... like this:
if ( 0 <= ["apple","banana"].indexOf(a) ) { ... }
The other thing you can do is using in operator. Also as it checks only against the keys, you can leave the values empty like this:
if ( a in { "apple": "", "banana": "" } ) { ... }
If you have lot's of options, obviously it's better to do the following:
var options = {
"apple": "",
"banana": ""
}
if ( a in options ) { ... }
Personally I think with just two options to check, this will be more readable for a human-eye to go for two separated checks, and I think in your examples you don't really need to shorten the if statements as they're already quite short and readable in my opinion.
if ( "apple" === a || "banana" === a ) { ... }
If you want a clean way to check if a variable equals any of a number of other variables, try using a function like this:
http://jsfiddle.net/aYRmL/
function equalsAny (first) {
return !![].slice.call(arguments, 1).filter(function (val) {
return first === val;
}).length;
}
The first argument is the one being compared to the rest. Use it like this:
var a = 'banana', b = 'orange';
equalsAny(a, 'banana', 'apple'); // returns true
equalsAny('orange', a, b); // returns true
The first one above accomplishes what you were trying to do with a == ('banana' || 'apple'). The seconds accomplishes what you were trying to do with (a || b) == 'banana'.
As an alternative solution you can use some or every:
var __slice = [].slice;
function any(a) {
return __slice.call(arguments,1).some(function(x) {
return a === x;
});
}
function all(a) {
return __slice.call(arguments,1).every(function(x) {
return a === x;
});
}
And use like:
// Instead of:
// if (a == 'banana' || a == 'apple' || a == 'orange')
if (any(a, 'banana', 'apple', 'orange')) {
...
}
// Instead of:
// if (a == 'banana' && b == 'banana' && c == 'banana')
if (all('banana', a, b, c)) {
...
}
(a || b) == 'banana' always will be false because (a || b) will return a Boolean witch is not equal to a string
UPDATE :
did some testing (a || b) always returns the first operand (a in this case) witch is 'apple' and not equal to 'banana'.
|| and && will give excepted result only if the both operands are Boolean or can be cased to Boolean.
The way it's working is that a && b and a || b are always set to the value of one of the variables. a && b will always be set to the value of b unless a is false, in which case the answer must be false. Similarly a || b will be set to the value of a, unless a is false, in which case it will be set to the value of b. As elclanrs mentioned, this is because of short-circuit evaluation -- the first operand may determine the result, in which case there's no point in looking at the second operand.
When both a and b are strings, they will never be false unless the string is zero-length. So a || b will be 'apple' in your case, and a && b will be 'banana'.

Best and/or shortest way to do strict (non-type converting) <, >, <=, >= comparison in Javascript

In Javascript, the == comparison has a strict (non-type converting) version: ===. Likewise, != has the strict form !==. These protect you from the following craziness:
var s1 = "1",
i1 = 1,
i2 = 2;
(s1 == i1) // true, type conversion
(s1 != i1) // false, type conversion
(s1 === i1) // false, no type conversion
(s1 !== i1) // true, no type conversion
However, the other comparison operators have no equivalent strict modes:
(s1 < i2) // true, type conversion
(s1 <= i2) // true, type conversion
([] < i2) // true, wait ... wat!?
The obvious solution seems pretty verbose:
((typeof s1 === typeof i2) && (s1 < i2)) // false
Is there a more idiomatic (or just less verbose) way to do this in Javascript?
Reference: MDN Comparison Operators
There are no built-in operators for what you want, but you can always create your own functions. For example, for <:
function lt(o1, o2) {
return ((typeof o1 === typeof o2) && (o1 < o2));
}
lt("10", 11); // false
Another option, if you're only dealing with strings and numbers, is extending String.prototype and Number.prototype:
function lt(o) {
return ((typeof this.valueOf() === typeof o) && (this < o));
}
String.prototype.lt = lt;
Number.prototype.lt = lt;
"10".lt(11); // false
(11).lt("12"); // false
How about creating a Object and using it
var strictComparison = {
"<" : function(a,b) { return ((typeof a === typeof b) && (a < b)) },
"<=" : function(a,b) { return ((typeof a === typeof b) && (a <= b)) },
">" : function(a,b) { return ((typeof a === typeof b) && (a > b)) },
">=" : function(a,b) { return ((typeof a === typeof b) && (a >= b)) }
};
console.log(strictComparison["<"](5,"6")) ;
console.log(strictComparison[">"](5,6)) ;

Categories

Resources