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

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.

Related

What does var n = (t.currentDevicePixelRatio = e || ("undefined" != typeof window && window.devicePixelRatio) || 1); mean?

var n = (t.currentDevicePixelRatio = e || ("undefined" != typeof window && window.devicePixelRatio) || 1);
Can someone tell me what this means? I know "||" means "OR", and I know that an expression like
n = n || {}
is setting the value of n to an empty object if n is a falsy value. But what happens what you have an equals sign in there? And the second component is even more weird to me.
Let's add some whitespace to make it more readable:
var n = (
t.currentDevicePixelRatio = e
||
(
"undefined" != typeof window
&&
window.devicePixelRatio
)
||
1
);
JavaScript expressions are evaluated left-to-right, parentheses-first. So the evaluation order is:
Copy the value of e into t.currentDevicePixelRatio.
The value of e is then emitted by the assignment = statement.
If that value is falsy, then evaluate the right-hand-side of the ||:
So if e is not null (or undefined or an empty string) then that's that and the value of e is also assigned to n and the expression completes.
Otherwise, if window is defined (i.e. this script is running in a web-browser, as opposed to Node.js) then copy the value of window.devicePixelRatio into t.currentDevicePixelRatio and also into n.
If window.devicePixelRatio is undefined then use 1 for both t.currentDevicePixelRatio and n.
Here is how the individual steps break down to:
var n;
if (e) {
t.currentDevicePixelRatio = e;
n = t.currentDevicePixelRatio;
} else if ("undefined" != typeof window && window.devicePixelRatio) {
t.currentDevicePixelRatio = window.devicePixelRatio;
n = t.currentDevicePixelRatio;
} else {
t.currentDevicePixelRatio = 1;
n = t.currentDevicePixelRatio;
}

How can I simplify `(variableA && !variableB) || !variableA` expression in 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));

What does this condition do in ternary?

Javascript Ternary Condition
I have javascript with this condition, what is this?
var y = (typeof x !== undefined) ? x || 0 : 1;
This (typeof x !== undefined) ? x || 0 : 1; is going to return always true because the typeof operator will return a string.
That condition should compare a string as follow:
(typeof x !== 'undefined') ? x || 0 : 1;
var x;
var str = typeof x !== 'undefined' ? x || 0 : 1;
console.log(str);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Conditional (ternary) Operator explanation:
+--- When condition is true
|
| +--- When condition is false
| |
| |
v v
typeof x !== 'undefined' ? x || 0 : 1;
^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| +---- The condition should be:
| (x === undefined ? 1 : x || 0)
|
+--- Checks for the type of x
Code refactored
var x = 4;
var str = x === undefined ? 1 : x || 0;
console.log(str);// should return 4
var y;
str = y === undefined ? 1 : y || 0;
console.log(str);// should return 1
y = null;
str = y === undefined ? 1 : y || 0;
console.log(str);// should return 0
y = 5;
str = y === undefined ? 1 : y || 0;
console.log(str);// should return 5
y = 5-"5";
str = y === undefined ? 1 : y || 0;
console.log(str); // should return 0
.as-console-wrapper { max-height: 100% !important; top: 0; }
Docs
Conditional (ternary) Operator
typeof
First, there is an error with the condition:
(typeof x !== undefined)
because you are comparing a type against a value.
typeof always returns a string, while undefined is a value. So, whatever type x is, it will be returned as as string. Even if it's value is undefined, "undefined" (notice the quotes?) will be returned as its type and since the string "undefined" has a typeof === "string", the condition will actually branch into the true section, even when x actually is undefined.
So, it needs to be: (typeof x !== "undefined").
Or, you could test the value of x against the value undefined:
(x !== undefined)
But, you can't mix and match values and types.
Now, assuming we correct that, the next part (the true branch):
x || 0
Simply returns x, as long as it is not "falsy" (that is, any value that would convert to the Boolean false). 0, false, NaN, undefined, "" or null are all falsy. So, if x is not falsy, x is returned. If x is falsy, then 0 is returned. This is a way to provide a default return value in case the first value doesn't exist. But, the logic is a bit off here, because if the code has entered the true branch, it's because x is not undefined, which means it's "truthy". And, if it's truthy, then we can safely just return x. So, it really should just be:
x
Finally, the last part (the false branch)
1
Is what will be returned if the original condition is false. In this case, if x is undefined.
So, the code has flaws in it and really should be:
(typeof x !== "undefined") ? x : 1
EXTRA CREDIT:
In reality, any expression you place into the condition of an if statement is going to be converted to a Boolean for the if to do its job. If all you need to know is if x is not a "falsy" value, then all you need to do is write:
x ? x : 1;
The x will be converted to a Boolean.
If it's true (truthy), then x is returned.
If it's false (falsy), then 1 is returned.
Examples:
function testX(x){
return x ? x : 1;
}
// Truthy:
console.log(testX(10)); // 10
console.log(testX({})); // {}
console.log(testX(true)); // true
console.log(testX("something")); // "something"
// Falsy:
console.log(testX("")); // 1
console.log(testX()); // 1
console.log(testX(4-"Z")); // 1 because 4-"Z" == NaN
console.log(testX(false)); // 1
console.log(testX(0)); // 1
console.log(testX(null)); // 1
The condition
(typeof x !== undefined)
asks if x is not of type undefined. Or, if x is defined. This will include any value or even null.
...? x || 0
If so, the expression evaluates to this. Which is the value of x in most cases or 0 if x is anything evaluated to be boolean false, e.g., null, false, etc.
... : 1;
Otherwise (i.e. case when x is undefined), evaluates to 1.
Typing in Javascript is complicated (in my opinion), sometimes it is not easy to remember what it is when you're comparing mixed type stuff, see https://dorey.github.io/JavaScript-Equality-Table/ for a summary matrix.
Admitting that you have a left-hand operand, it does the same thing as :
var y;
if(typeof x !== undefined) {
if(x)
y = x;
else
y = 0;
}
else
y = 1;

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'.

Explain a block of crazy JS code inside Sizzle(the CSS selector engine)

So, here is the function for pre-filtering "CHILD":
function(match){
if ( match[1] === "nth" ) {
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
// calculate the numbers (first)n+(last) including if they are negative
match[2] = (test[1] + (test[2] || 1)) - 0;
match[3] = test[3] - 0;
}
// TODO: Move to normal caching system
match[0] = done++;
return match;
}
The code is extracted from line 442-458 of sizzle.js.
So, why is the line var test = ..., have the exec inputing a boolean? Or is that really a string?
Can someone explain it by splitting it into a few more lines of code?
The exec method will receive a string, because the Boolean Logical Operators can return an operand, and not necessarily a Boolean result, for example:
The Logical AND operator (&&), will return the value of the second operand if the first is truthy:
true && "foo"; // "foo"
And it will return the value of the first operand if it is by itself falsy:
NaN && "anything"; // NaN
0 && "anything"; // 0
The Logical OR operator (||) will return the value of the second operand, if the first one is falsy:
false || "bar"; // "bar"
And it will return the value of the first operand if it is by itself non-falsy:
"foo" || "anything"; // "foo"
Falsy values are: null, undefined, NaN, 0, zero-length string, and of course false.
Anything else, evaluated in boolean context is truthy (will coerce to true).
So, let's look the expression:
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] === "even" && "2n" || // return '2n' if match[2] is 'even'
match[2] === "odd" && "2n+1" || // return '2n+1' if it's 'odd'
!/\D/.test(match[2]) && "0n+" + match[2]|| // return '0n+N' if it's a digit(N)
match[2] // otherwise, return the match[2] value
);

Categories

Resources