I have been using MDN Docs - Logical Operators as a frame of reference to understand the logical AND operator.
I have understood most of these code examples especially the first 4 as shown here:
a1=true && true // t && t returns true
a2=true && false // t && f returns false
a3=false && true // f && t returns false
a4=false && (3 == 4) // f && f returns false
a5="Cat" && "Dog" // t && t returns Dog
a6=false && "Cat" // f && t returns false
a7="Cat" && false // t && f returns false
However I am having issue understanding a5, a6 and a7.
I am failing to understand how the two strings a5="Cat" && "Dog" are evaluating to true && true returns Dog
I am also failing to understand why the string "Cat" is evaluating to true as part of a6=false && "Cat" // f && t returns false
All non-empty strings are true when evaluated as boolean values.
In a6=false && "Cat" the string "Cat" is not evaluated at all, as the left side is false.
First of all lets look at a5:
a5="Cat" && "Dog"
Which returns dog, the mdn-docs states that AND(&&):
Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
Since a non-empty string can't be converted to false, it will return dog, if you change the order of dog and cat, it will ofcourse return cat.
In a6 false, is false and thus it returns false because of this:
Returns expr1 if it can be converted to false...
In a7 cat is true and thus it goes on to the next expression which is false, and thus returns false.
...otherwise, returns expr2
In a && b sentence a is evaluated first, and if a is true, then b is evaluated.
(a5 = "Cat") returns "Cat" which is true (only empty strings are false), so Dog is returned.
(a6 = false) returns false, so the second "Cat" part is not evaluated.
(a7 = "Cat") is true, so the second false part is returned.
Related
I was convinced that any logical expression in Javascript will return a boolean value, yet this expression returns a number 0 instead of a bool:
0 && true
> 0
Why is that so? How do I approach logical expressions in Javascript in this case to prevent this kind of mistake in the future?
Background story - I was baffled by this statement in jQuery:
$('.something').toggle(0 && true);
It doesn't toggle the element because '0' is returned, and not a boolean!
Maybe there are some clever reasons why this is so, but can't say I like it.
The documentation about the && operator says:
expr1 && expr2: Returns expr1 if it can be converted to false; otherwise, returns expr2.
This is why is returns the first value: 0
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Description
You expected as a result false (a boolean), however the boolean value of the resulting value is falsy too. This means that you can use it in a condition (if) and have the expected behavior.
If you need to store it in a variable and prefer to have a boolean value, you can convert it. This can be done using a double negation: !!
!!(0 && true)
Or using Boolean:
Boolean(0 && true)
As #Maxime Chéramy noted, JavaScript checks if the first element returns false and it doesn't really check the second one. This saves calculation time.
JS does not need to check both statements if the first is false it will not check the second one, it will just return the first one. If the first is true, again, it doesn't check the second one, it just returns it.
A number, object, array, or string are truety.
Use Boolean() to get a Boolean value or use the short method !!()
'banana' && true // returns true
but
true && 'banana' // returns 'banana'
Boolean(true && 'banana') // returns 'true'
!!(true && 'banana') // returns 'true'
with three
true && 'banana' && 1 // returns 1
true && 1 && 'banana' // returns 'banana'
1 && 'banana' && true // returns true
Boolean(true && 'banana' && 1) // returns 'true'
!!(1 && 'banana' && true) // returns 'true'
Why does the following code produce a == 3?
var x = "abc";
var y = 3;
var z = "xyz";
var a = x && y || z;
http://jsfiddle.net/thinkingmedia/qBZAL/
I would have expected this to result in a == true.
Why is the logical operator evaluating "abc" as true but doesn't evaluate 3 as true. Instead it produces 3 as the result.
Furthermore, if you change y = 0 then a == "xyz" which means that && treated 0 as false. What happen to treating a number as a number?
What's going on here with the logical operators?
This is to be expected.
In JavaScript (and many other languages), not only Booleans themselves are true or false, but other objects can be truthy or falsey as well (See the docs on mdn):
The value […] is converted to a boolean value, if necessary. If value is […] is 0, -0, null, false, NaN, undefined, or the empty string (""), [it is] false. All other values, including any object or the string "false", create […] true.
The logical operators || and && don't return true or false, rather they return the last argument to influence whether they are truthy or falsey (reference):
expr1 && expr2 – Returns expr1 if it can be converted to false; otherwise, returns expr2. Thus, when used with Boolean values, && returns true if both operands are true; otherwise, returns false.
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; if both are false, returns false.
The first step is to evaluate "abc" && 3.
false && 3 would return false,
true && 3 would return 3.
"abc" is not false, so JavaScript takes the second part, i.e. 3.
The second step is to evaluate 3 || "xyz". Here, JavaScript takes the first value which is not null, i.e. 3. This is similar to this.firstObject ?? this.defaultValue in C#: the second part is taken only when the first part is null.
the side effect is that you can do things like this:
x = x || {};
to set a variable to a default if it is not set.
Or
TrackingManager && TrackingManager.track("user was here")
to avoid bulkier if statements.
In my code I assumed the following || short-circuiting was safe:
var $holidayExpandBarOrOpeningHours =
$(".expandBar + .holidayHours_c").prev() || $(".openingHours");
But to my surprise if we short-circuit an empty array with a true statement an empty array is still returned. I will demonstrate with some console code below and my question is why [] || true evaluates to [].
false || "expected"
"expected"
false == []
true
[] || "expected"
[]
typeof([])
"object"
({}) || "expected"
Object {}
({}) == false
false
{} == false
SyntaxError: Unexpected token ==
Part of me thinks that it is because an array is an object which evaluates to true, however if that was the case than based on ({}) == true one would expect [] == true.
Last thing I would like to note is the outcome is the same when using use 'strict' mode.
When converted to a boolean value, [] is true.
> !![]
true
> ![]
false
When converted to a number, [] is 0. That's why comparing it with false returns true: when comparing two values of different types, JavaScript first converts both to numbers and then compares the numbers.
> +[]
0
> +false
0
> +[] == +false
true
This is because || and use == different rules for the conversion.
The logical-or uses ToBoolean while the equality equals uses ToNumber/ToPrimitive.
From 11.11 Binary Logical Operators:
3) If ToBoolean(lval) is true, return lval.
Since ToBoolean([]) is true, [] || x results in []. This is also why if([]) { /* this runs */ }: arrays in JavaScript are "truthy" values.
From 11.9.3 The Abstract Equality Comparison Algorithm:
7) If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
9) [..then] If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
5) [..then] If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
The logic applied to [] == true is ToNumber(ToPrimitive([])) == ToNumber(true).
And the conversion values:
ToBoolean([]) is true
ToNumber(true) is 1
ToPrimitive([]) is an empty string (from DefaultValue/toString)
So:
ToNumber(ToPrimitive([])) == ToNumber(true)
ToNumber("") == 1
0 == 1
false
(Which is a long way to say what John Kugelman said.)
Also, ({}) == true is normally false and follows the same conversions as above.
Under a default environment, ToPrimtive({}) returns a non-empty string (i.e. "[object Object]" as per Object.prototype.toString). This string will evaluate to NaN after ToNumber such that NaN == 1; or false.
See Why an empty Array type-converts to zero? +[] for more details on the ToPrimitive conversion.
An empty array is an object; objects coerced to booleans are true. So
({}) || true; // -> {}
[] || true; // -> []
"" || true; // -> true (empty strings are coerced to false)
Sidenote - the parentheses around {} are required to avoid parsing it as a block.
I've just answered this question but I don't understand why it works the way it does.
Basically the problem can be simplified to this:
var b = new Boolean(false);
console.info(b == false); // Prints "true" - OK
console.info(b && true); // Prints "true" - but should be "false"
I assume there's some unintuitive automatic casting going on but I don't understand it would sometime be automatically casted to true, sometime to false. Any idea?
I guess this illustrates the problem better:
> false && 123
false // OK
> new Boolean(false) && 123
123 // ???
== does a lot of coercion:
Object == false =>
Object == 0 =>
Object.valueOf() == 0 =>
false == 0 =>
0 == 0 =>
true
Or if you follow the steps in the algorithm, it is
Step 7, Step 9, Step 6, Step 1 c iii.
The logical and just goes directly for ToBoolean, which always returns true for objects.
Note that new Boolean returns an object and not a boolean value.
Maybe the object b is true when doing (b && false) but doing to logical operation of true and false results to false.
If you do this:
var b = new Boolean(false);
console.info(b == false); // Prints "true" - OK
console.info(b && true); // Prints "true"
So even though the object b was set to false in the (b && true) it results to true because it exists and it's not set to null.
False AND False is false. Truth tables - AND only returns true if both arguments are true, and neither is in this case.
EDIT: True AND False is also false, so anything && False is false.
I'm not sure if I understand your question correctly but it look like the major issue derives from the fact that if (new Boolean(false)) evaluates to true. If you put expressions in an if statement or link them with logical operators (i.e. &&), JavaScript only checks if they are truthy or falsy. When it comes to boolean primitives, it is easy:
true -> truthy
false -> falsy
But when it comes to boolean objects, it looks different:
new Boolean(false) -> truthy
new Boolean(true) -> truthy
The reason for this is, that in JavaScript, every object (if not null) is truthy.
I have a method hitTest that check for collision detection and can return a Point object (if a collision is happened) or (if there is no collision) it returns null or undefined (i haven't deeply understand when it return null or undefined but i trust chrome console).
I have to test collision on 2 objects. And check if one or the two collisions are happening. I have tried this code:
var result1 = hitTest(player, object1);
var result2 = hitTest(player, object2);
if( result1 || result2 ) { blabla() };
but it doesn't work.
now.. i know that js is reallly a tricky language and i think about a smart way to do this without writing typeof 4 times. I'm thinking about python short-circuit logical operators...
You can use &&, it returns the first detected false/null/undefined/0, i.e. if won't pass, if either result1 or result2 is null.
for this type of thing, underscore.js is beautifull: http://underscorejs.org/#isNull and http://underscorejs.org/#isUndefined
I use these helpers frequently to get around edge cases in JS such as the ones you mentioned
You wouldn't need to write typeof 4 times already but anyway;
Coercion paradigm for conditional statements and operators:
//TYPE //RESULT
Undefined // false
Null // false
Boolean // The result equals the input argument (no conversion).
Number // The result is false if the argument is +0, −0, or NaN; otherwise the result is true.
String // The result is false if the argument is the empty String (its length is zero); otherwise the result is true.
Object // true
From Mozilla:
Logical AND (&&)
expr1 && expr2
If the first operand (expr1) can be converted to false, the && operator returns false rather than the value of expr1.
Logical OR (||)
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; if both are false, returns false.
true || false // returns true
true || true // returns true
false || true // returns true
false || false // returns false
"Cat" || "Dog" // returns Cat
false || "Cat" // returns Cat
"Cat" || false // returns Cat
true && false // returns false
true && true // returns true
false && true // returns false
false && false // returns false
"Cat" && "Dog" // returns Dog
false && "Cat" // returns false
"Cat" && false // returns false
Additionally, you can use a shortcut isset() method just like in PHP to properly validate your objects:
function isSet(value) {
return typeof(value) !== 'undefined' && value != null;
}
So; your code would be:
var result1 = hitTest(player, object1),
result2 = hitTest(player, object2);
if ( isSet(result1) && isSet(result2) ) { blabla(); };