So in most cases I've been able to use something similar to these lines, but Javascript has given me this weird result.
If I take some value and it turns out to be undefined, when compared to an integer, it does not appear to be less than or greater than any number. Why is this?
if(undefined < 1 || undefined >= 1)
alert("yes");
else
alert("no");
//this always alerts no
JSFiddle
There is no operator '<' can not be applied to type 'undefined' error in JavaScript as you would find in other typed languages. As such, JavaScript evaluates incompatible types with an operator to false.
That's just how javascript works. If either side can't be converted to a number (strings can, by code point comparison: '2' < '3' && '186' < '4'), than number comparisons will return false (works with >, <, <=, >=).
Might be a little tangential, but I'd like to introduce null into this topic to demonstrate an elusive pitfall.
When using <, <=, >, >= with null or undefined, the result is generally considered to always be false. However, there's one exception: Infinity
console.log(undefined < Infinity); // false, as expected
console.log(null < Infinity); // true, surprise!
Also notably, this also applied to the string "Infinity"
console.log(undefined < "Infinity"); // false
console.log(null < "Infinity"); // true, surprise again!
console.log(null < "infinity"); // false, it's case-sensitive
I discovered this weird behavior accidentally, and have no idea why the hell JavaScript behaves this way. But anyway, like it or not, this is JavaScript.
Hopefully, this may help someone one day.
Related
Try to learn short circuiting and doing some assignments . Have the following code
game.odds.team1 < game.odds.team2 && `${game.team1} is more likely to win` || `${game.team2} is more likely to win`
My understanding was that && operator treats left-side as 1 part of expression and whole right side as a 2nd part. So I don't quite understand why this returns {game.team2}.... in the end.
Could you help me clarify this please?
P.S. Just to be more precise, the code above works well and does what it has to do, but I struggle to understand how exactly it works and why it works this way.
EDIT: the previous solution has been removed according to your question
As you only need to understand how short-circuit evaluation of logical operator works, so I will add the following explanation:
I - Keypoints:
1- logical AND operator && returns the first falsy value, and if all operands were evaluated, it returns the last one.
2- logical OR operator || returns the first truthy value, and if all operands were evaluated, it returns the last one.
3- The precedence of AND && operator is higher than OR ||
4- Check the table list of JS operators precedence
In your example, both operands (arguments) of the logical OR are truth (strings).
II - Example:
Starting from your code, let's consider this object of values:
const game = {
odds: {
team1: 10,
team2: 3
}
}
const winner = game.odds.team1 < game.odds.team2 && `$team1 is more likely to win` || `team2 is more likely to win`
console.log(winner)
Here, winner will be assigned to the last operand. But why? Let's break-down the logic (remember the keypoints):
1- game.odds.team1 < game.odds.team2 is false and $team1 is more likely to win is truthy as it's a string, then && will return the first falsy value.
2- game.odds.team1 < game.odds.team2 is returned (still false). and it's evaluated now with team2 is more likely to win which is a truthy string.
3- the logical OR return the first truthy value, therefore team2 is more likely to win is assigned to winner.
I hope it's clear now
The problem of this code is to have three parts which can change the result.
a < b && c || d
^^^^^ ^ ^
This answer takes the terms truthy and falsy especially for part c and d.
If the first condition a < b is true, it takes c as long as c is truthy. If not, it takes d.
If the first condition is false, it takes d, because of the short circuit &&.
For having a better understanding, here a table of truth. (- means value does not matter):
a < b
c
d
result
true
truthy
-
c
true
falsy
d
d
false
-
d
d
My understanding was that && operator treats left-side as 1 part of expression and whole right side as a 2nd part
No, it doesn't. The && has a higher precedence than the ||. It's parsed as
((game.odds.team1 < game.odds.team2) && `${game.team1} is more likely to win`) || `${game.team2} is more likely to win`
But yeah, while it's a nice exercise you definitely should use the ?: conditional operator for this :-) Apart from expressiveness, another reason is that c ? t : e is not always equal to c && t || e. Can you figure out for which values of t that might be?
Consider this condition:
(true & true & false & false & true) == true //returns: false
As you can see, the bitwise AND behavior is exactly like logical AND's:
(true && true && false && false && true) == true //returns: false
I'm wondering why I should use logical operations when the bitwise operations do the same as the logical ones.
Note: Please don't answer that's because of performance issue because it's pretty much faster in Mozilla Firefox, see this jsPerf: http://jsperf.com/bitwise-logical-and
The most common use of short-circuit evaluations using logical operators isn't performance but avoiding errors. See this :
if (a && a.length)
You can't simply use & here.
Note that using & instead of && can't be done when you don't deal with booleans. For example & on 2 (01 in binary) and 4 (10 in binary) is 0.
Note also that, apart in if tests, && (just like ||) is also used because it returns one of the operands :
"a" & "b" => 0
"a" && "b" => "b"
More generally, using & in place of && is often possible. Just like omitting most ; in your javascript code. But it will force you to think more than necessary (or will bring you weird bugs from time to time).
bitwise operations behavior the same?
No, it's not. Bitwise operators work on integer numbers, while the logical operators have stronlgy different semantics. Only when using pure booleans, the result may be similar.
Bitwise operators: Evalutate both operands, convert to 32-bit integer, operate on them, and return the number.
Logical operators: Evaluate the first operand, if it is truthy/falsy then evalutate and return second operand else return the first result. This is called Short-circuit evaluation
You already can see this difference in the type of the result:
(true & true & false & false & true) === 0
(true && true && false && false && true) === false
No they don't do the same. The differences are:
Whether the operand types are converted
Whether both operands are evaluated
The return value
// sample functions
function a() { console.log("a()"); return false; }
function b() { console.log("b()"); return true; }
&& (Logical AND)
Checks the truthiness of operands
Uses short-circuiting and may not evaluate the second operand
Returns the last evaluated operand without type conversion
a() && b();
// LOG: "a()"
// RET: false
& (Bitwise AND)
Temporarily converts the operands to their 32bit integer representation (if necessary)
Evaluates both operands
Returns a number
a() & b();
// LOG: "a()"
// LOG: "b()"
// RET: 0
Almost everything is already said, but just for completeness' sake I want to take a look at the performance aspect (which you said doesn't matter, but it very well might):
JavaScript has a lot of difficult-to-remember rules on how to evaluate expressions. This includes a lot of type casting (implicit type coercion) when it comes to more complex comparisons. Arrays and Objects need to be converted by calling their toString() methods and are then cast to numbers. This results in a huge performance hit.
The logical operator && is short-circuiting. This means as soon as it encounters a falsy value, the evaluation stops and false is returned. The bitwise operator will always evaluate the entire statement.
Consider the following (yes, quite extreme) short circuit example when very expensive operations (casting an array and an object) are involved: ( performance according to https://jsbench.me in Chromium 90)
// logical operator
( false && {} && [] ) == true
// /\ short circuits here
// performance: 805M ops/sec
// bitwise operator
( false & {} & [] ) == true // evaluates the entire statement
// performance: 3.7M ops/sec
You can see that the performance differs by a factor of 100!
Because using && or & convey different intents.
The first says you're testing truthiness.
The second means your conjuring up some bit magic. In real code, you will be looking at variable1 & variable2. It will not be clear that you're in fact intending to test for truth (not truthiness). The reader of the code will probably be confused because it's not obvious why & was used.
Furthermore, the semantics are completely different when taking into account other values than bools and function calls, as pointed out by numerous other posts.
Boolean allows short-circuiting, which can be a performance boost or safety check.
Non-boolean values used in the conditional. For example, if ( 1 & 2 ) will return false, whereas if ( 1 && 2 ) will return true.
You can't short-circuit bitwise operators. Also the bitwise operators can do much more, not just compute a boolean expression.
There's a huge difference: logical operations are short circuited. It means that (true && true && false ) is the last thing to be executed. This allows powerful constructs, such as abstract factory model using var myFunc = mozilla.func || opera.sameFunc || webkit.evenOneMoreVariationOfTheSameConcept;
All subexpressions of bitwise operations have to be fully evaluated -- and btw. one only rarely needs to evaluate constant bitwise or logical expressions anyway.
First condition have to convert first and sum bits then. But second will check logical and return value.
So First one will be slower than second one.
Run This Test: http://jsperf.com/bitwise-logical
on Chrome & IE Bitwise is slower
but on FireFox logical is slower
Bitwise operators (& and |) converts the two operands to 32 bit "integers" and return the bit operation as a result. The conversion of an operand is 0 if it is not numeric.
The logical operators (&& and ||) are not logical at all, but rather are selectors of one of the operands or 0.
The logical && returns the first operand if both exist, otherwise 0
The logical || returns the first existing operand, otherwise 0
An operand exists if not: undefined, null, false, or 0
var bit1 = (((true & true) & (false & false)) & true), // return 0;
bit2 = (((true && true) && (false && false)) && true); // return flase
alert(bit1 + ' is not ' + bit2);
I was explaining to a colleague that you should use === and !== (and >== and <== of course) when comparing variables in JavaScript so that it doesn't coerce the arguments and get all froopy and confusing but they asked me a two part question that I did not know the answer to and thought I would ask the experts here, specifically it is:
What about > and < - when they compare do they also coerce the arguments or not - why isn't there some sort of >> and << operator (probably need to be some other syntax as I would guess they would be bit shift operators if it is going along the whole C style but you get the gist)?
So I can write a test to find the answer to the first part, which I did, here it is:
// Demo the difference between == and ===
alert(5 == "5");
alert(5 === "5");
// Check out what happens with >
alert(5 > "4");
alert(5 > 4);
and it returned:
true
false
true
true
so it does look like the > is doing the coercion since > "4" and > 4 return the same result. so how about the second part...
Is there some sort of operator for > and < that do not coerce the type (or how can I change my test to perform the test safely)?
No, there's no need for such operators. The type checking done for those relational operators is different than for equality and inequality. (edit — perhaps it's a little strong to say that there's "no need"; that's true only because JavaScript deems it so :-)
Specifically, the > and < and >= and <= operators all operate either on two numeric values, or two strings, preferring numeric values. That is, if one value is a number, then the other is treated as a number. If a non-number can't be cleanly converted to a number (that is, if it ends up as NaN), then the result of the comparison is undefined. (That's a little problematic, because undefined will look like false in the context of an if statement.)
If both values are strings, then a collating-order string comparison is performed instead.
If you think about it, these comparisons don't make any sense for object instances; what does it mean for an object to be "greater than" another? I suppose, perhaps, that this means that if you're finding yourself with values of variant types being compared like this, and that's causing problems, then yes you have to detect the situation yourself. It seems to me that it would be good to work upstream and think about whether there's something fishy about the code that's leading to such a situation.
Is there some sort of operator for > and < that do not coerce the type
No.
how can I change my test to perform the test safely
You would have to explicitly test the types:
typeof a === typeof b && a > b
I referenced Flanagan's JavaScript: The Definitive Guide (5th Ed.) and there does not seem to be non-coercive comparison operators.
You are right in saying the << and >> are indeed bitwise operators so that wouldn't work.
I would suggest you deliberately coerce the values youself:
var num_as_string = '4';
var num = +num_as_string;
if (5 > num) { ... }
12 > '100' // false
'12' > 100 // false
'12' > '100' // true
As others mentioned, if one is a number the other is casted to a number. Same rule applies to these cases as well:
null > 0 // false
null < 0 // false
null >= 0 // true
However, there might be cases that you would need null >= 0 to give false (or any of the number string comparison cases above), therefore it is indeed a need to have strict comparison >== or <==.
For example, I am writing a compareFunction for the Array.prototype.sort() and an expression like x>=0 would treat null values like 0's and put them together, whereas I want to put them elsewhere. I have to write extra logic for those cases.
Javascript says deal with it on your own (in practice).
I would like to find a way to programmatically (i.e. by writing code) find for what values of x we have the expression x == null evaluating to true.
It is impossible to (without prior knowledge of at least the basic JavaScript rules) be able to programmatically determine all values of x for which x == null is true. However, the following should show a pattern from which a heuristic can be derived:
var v = [null, undefined, false, true, -1, 0, 1, "", " ", "0", {}, []]
for (var i = 0; i < v.length; i++) {
var x = v[i]
alert(x + " == null? " + (x == null))
}
(This particular test case does cover all the times when it would be true.)
Similar tests can be done for == false, etc.
Happy coding.
See Ray Toal's answer for more suggestions of test values.
In the absence of knowing at least something about how JavaScript performs type conversions the way these conversions are applied over the operator == you would have to test every possible value against null, and the number of possible values are unlimited, so what you ask cannot be done.
With a little bit of knowledge you can break down the world of all possible JavaScript expressions into the following categories:
undefined
null
true
false
0
negative finite numbers
positive finite numbers
negative infinity
positive infinity
NaN
empty string
a string full of whitespace
a string with at least one non whitespace character
an empty object
an object with some properties
Test a representative value from each class against null and see what you get.
I assume from the way the question was phrased that you know the exact section in the ECMA-262 specification that defines, precisely, the semantics of ==. ( Section 11.9.3 of the 5.1
spec )
I found a bug in a script that was written, and I'm having troubles figuring out exactly what is causing the issues. Specifically:
"49px" < 50 === false
There's two different conversions I can think of here:
49 < 50 === true
"49px" < "50" === true
"49" < 50 === true // just for the hell of it
I fixed it with:
parseInt("49px") < 50 === true
So why does this evaluate to false? What exactly is happening here?
If one operand is a number and another operand is a string, then the string is converted to a number and then the comparison is made.
If the string cannot be converted to a number, it gets converted to NaN, and the comparison always returns false.
When javascript is asked to compare a number with something else, it tries to convert that "something else" to a number. In this case, "49px" evaluates to NaN so NaN < 50 is false.