This question already has answers here:
[] == ![] evaluates to true
(5 answers)
Closed 4 years ago.
var arr = [];
Boolean(arr) // true
Boolean(!arr) // false
arr == arr // true
arr == !arr // true ??? what ???
I do not want to get the answer that 'recommend using === instead of =='.
I would like to know the reason for this phenomenon and the principle of type conversion of JavaScript.
Type conversion in JS, particularly with regards to loose equality, is a tricky beast.
The best place to always start when answering the question "why does this particular loose equality evaluate this way" is to consult this table of equality comparisons by operand type.
In this case, we can see that for [] == false, Operand A is an Object and Operand B is a Boolean, so the actual comparison performed is going to be ToPrimitive(A) == ToNumber(B).
The right side of that is simple; ToNumber(false) evaluates to 0. Done and done.
The left side is more complex; you can check the official ECMAScript spec for full documentation of ToPrimitive, but all you really need to know is that in this case it boils down to A.valueOf().toString(), which in the case of the empty array is simply the empty string ""
So, we end up evaluating the equality "" == 0. A String/Number == comparison performs ToNumber on the string, and ToNumber("") is 0, so we get 0 == 0, which is of course true.
Double equals, ==, performs an amount of type coercion on values before attempting to check for equality.
So arr == arr returns true as you'd expect as what you are actually checking is if [] == [] and both sides of the equation are of the same type.
arr == !arr is actually checking if [] == false. The == then performs type coercion on the [] value. This does not, as Hamms pointed out, perform a boolean conversion, instead [] is turned into a primitive, which is an empty string due to reasons. So now our equation is '' == false. The types on the two sides of this operation are still not the same. So the type coercion kicks in again, and due to truthy and falsey values in javascript, '' also evaluates to false. The equation now becomes false == false, which is obviously true.
Related
This question already has answers here:
If ([] == false) is true, why does ([] || true) result in []?
(3 answers)
Closed 7 years ago.
At least in JavaScript the following are true:
0 == [] // true
0 == false // true
![] == false // true
Why is that? I know that == means equals but not equals in type, but how is false == true, so to speak, in that case?
JavaScript coerces objects to boolean values when using the non-strict equality operator.
0 == []
because JavaScript coerces both of the values (both of which are not of the same type) to boolean values to compare them. In other words, false == false.
If you use ===, on the other hand, you're checking object equality.
An interesting use case would be this:
[] === []; // => false
This is because === is checking the memory location of the objects. Two arrays don't share the same memory location. However:
var arr = [];
arr === arr; // ==> true
But, here's another interesting twist:
1 === 1; // ==> true
In the case of arrays and plain objects, JavaScript references the memory location. But with values like strings and numbers, JavaScript checks whether the values are absolutely equal with the === operator.
So the big difference comes down to differences in == and ===, and how JavaScript coerces types.
Hint: This is why it's usually recommended that you use the strict === operator if you need to prevent coercion (however, sometimes coercion can work to your benefit, for example when working with cross-browser issues where a value might be undefined in one browser but null in the other browser. Then you can say something like !!thatStrangeValue, and both undefined and null will be coerced to the same thing).
Edit
OP brought up a good point:
[] == false;
![] == false;
The above statements are both correct, which is strange. I would say the first statement is checking for emptiness, while the second one is checking for existence. Anyone know the answer to this last point?
In JavaScript, there are two types of equality. There is equality of value which is represented by == and equality of value and type, which is represented by ===. The latter is the strict equality operator.
In your case, we are checking equality by value only, not type.
[] represents an empty object, meaning [] and 0 have the same value.
In JavaScript, the value of any number greater than or equal to 1 is true and the value of 0 is false
Hope this helps
I've encountered something which seems inconsistent on the part of the interpreter, though I know it probably makes sense and I just don't understand it. It has to do with evaluating the equality of a truthy/falsy values and Booleans.
Example 1:
if (document.getElementById('header')) {
//run code here
}
If the element with an id of 'header' is found in the document, the condition is true because the presence of an object is considered truthy.
Example 2:
if (document.getElementById('header) == true) {
// run code here
}
Presuppose the referenced element is found within the document. It was explained to me that this condition will evaluate to false because a truthy value does not equal a Boolean value of true.
This doesn't seem to make sense. The presence of the object is considered truthy due to type coercion, so therefore it should equal true even though the data types are different.
Consider the following:
(false == 0) // evaluates to true
(false === 0) // evaluates to false
This is a case where false equals 0 is true when you use the equals to operator. Because 0 is considered a falsy value, it is equal to the Boolean value of false. The values are the same and the data types are different.
To me, (document.getElementById('header') == true) and (false == 0) are the same thing. And yet, they both evaluate to something different.
Can someone please explain to me why this is the case? I've been reading different descriptions of this, but no one seems to explain it in-depth.
document.getElementById('header') returns a DOM object or null. So, in your second comparison (assuming it is resolving to an object), you're comparing:
if (obj == true)
A DOM object is not == to true.
To see why, you have to go to the ECMAScript rules for automatic type conversion which you can see in the ECMAScript 5 specification here: http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3.
The operative rules when comparing an object == boolean are all the way down to rules 9 and 10.
If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
Return false.
Rule 9 is the first rule where Type(x) is Object and the two types are not the same, so it's the first one to check.
Since Type(y) is Boolean, it does not pass rule 9.
Thus, when it hasn't passed any rules 1-9, it evaluates to false.
When you do this comparison:
(false == 0) // evaluates to true
you're looking at rule #6 in the type conversion rules which will do:
ToNumber(false) == 0
which will resolve to:
0 == 0
which will be true.
For this one:
(false === 0)
Whenever you use ===, if the two types are different, then the result is immediately false so this evaluates to false. === requires type AND value to be the same so if the type is not the same, then it doesn't even attempt to compare the value. No type conversion is ever done with === which is one of the useful reasons to use it.
You should understand that the truthy and falsey rules apply to only a single check like this with no == or === in the comparison:
if (obj)
They do not apply when you are comparing x == y. For that, you have to refer to the type conversion rules in section 11.9.3 of the specification (linked above).
Presuppose the referenced element is found within the document. It was explained to me that this condition will evaluate to false because a truthy value does not equal a Boolean value of true.
You're right, it doesn't make sense because whoever explained that to you is wrong.
The presence of a DOM element will evaluate to true and if it doesn't exist, it will evaluate to false (with a double-equals vs. triple). If in the event they are using triple equals, you can simply try:
!!document.getElementById('someNodeId') and it will return a boolean value.
You can always try this in the console if you want to be sure.
!!document.getElementById('notify-container');
>> true
!!document.getElementById('non-existing-node-goes-here');
>> false
Edit: I didn't read the example clearly or the example was updated. Yeah, you're using double equal. The element is truthy, but it's not "true".
When the if() statement is executing, it's checking if there is a truthy value inside the parenthesis. The == operator is checking whether the two values are equal in nature. In JavaScript, true and false are == to 1 and 0, respectively; hence why you can type (4 + true) and get 5, or false*6 and get 0!
When you type something == true, you're really checking if something == 1.
If something isn't a boolean value it's not going to be the same as 1.
Perhaps an explanation of your postulate "The presence of the object is considered truthy due to type coercion, so therefore it should equal true."
If any truthy value is equal to true,
then any truthy value is equal to any truthy value (by transitive property, a=b,c=b, therefore a=c),
however, this would not hold true for all cases! ("blue" == "green", 5 == "six" simply because they are each non-false values. This would make the == fairly worthless!)
The conclusion does not follow, so therefore the postulate is invalid. In general, you should use === if you need to check if two things are truly the same thing.
Hopefully this clears things up!
I was encountering a lot of bugs in my code because I expected this expression:
Boolean([]); to evaluate to false.
But this wasn't the case as it evaluated to true.
Therefore, functions that possibly returned [] like this:
// Where myCollection possibly returned [ obj1, obj2, obj3] or []
if(myCollection)
{
// ...
}else
{
// ...
}
did not do expected things.
Am I mistaken in assuming that [] an empty array?
Also, Is this behavior consistent in all browsers? Or are there any gotchas there too? I observed this behavior in Goolgle Chrome by the way.
From http://www.sitepoint.com/javascript-truthy-falsy/
The following values are always falsy:
false
0 (zero)
0n (BigInt zero)
"" (empty string)
null
undefined
NaN (a special Number value meaning Not-a-Number!)
All other values are truthy, including "0" (zero in quotes), "false" (false in quotes), empty functions, empty arrays ([]), and empty objects ({}).
Regarding why this is so, I suspect it's because JavaScript arrays are just a particular type of object. Treating arrays specially would require extra overhead to test Array.isArray(). Also, it would probably be confusing if true arrays behaved differently from other array-like objects in this context, while making all array-like objects behave the same would be even more expensive.
You should be checking the .length of that array to see if it contains any elements.
if (myCollection) // always true
if (myCollection.length) // always true when array has elements
if (myCollection.length === 0) // same as is_empty(myCollection)
While [] equals false, it evaluates to true.
yes, this sounds bad or at least a bit confusing. Take a look at this:
const arr = [];
if (arr) console.log("[] is truethy");
if (arr == false) console.log("however, [] == false");
In practice, if you want to check if something is empty,
then check the length. (The ?. operator makes sure that also null is covered.)
const arr = []; // or null;
if (!arr?.length) console.log("empty or null")
[]==false // returns true
This evaluates to true, because of the Abstract Equality Algorithm as mentioned here in the ECMA Specification #Section 11.9.3
If you run through algorithm, mentioned above.
In first iteration, the condition satisfied is,
Step 7: If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Hence the above condition transforms to -> [] == 0
Now in second iteration, the condition satisfied on [] == 0:
Step 9: If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
[] is an object, henceforth, on converting to primitive, it transforms to an empty string ''
Hence, the above condition transforms to -> '' == 0
In third iteration, condition satisfied, is:
Step 5: If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
As we know, empty string, '' is a falsy value, hence transforming an empty string to number will return us a value 0.
Henceforth, our condition, will transform to -> 0 == 0
In fourth iteration, the first condition is satisfied, where the types are equal and the numbers are equal.
Henceforth, the final value of the [] == false reduces to 0 == 0 which is true.
Hope this answers your question. Otherwise, you can also refer this youtube video
I suspect it has something to do with discrete math and the way a conditional (if then) works. A conditional has two parts, but in the instance where the first part doesn't exist, regardless of the second part, it returns something called a vacuous truth.
Here is the example stated in the wikipedia page for vacuous truths
"The statement "all cell phones in the room are turned off" will be true when no cell phones are in the room. In this case, the statement "all cell phones in the room are turned on" would also be vacuously true"
The wikipedia even makes specific mention of JavaScript a little later.
https://en.wikipedia.org/wiki/Vacuous_truth#:~:text=In%20mathematics%20and%20logic%2C%20a,the%20antecedent%20cannot%20be%20satisfied.&text=One%20example%20of%20such%20a,Eiffel%20Tower%20is%20in%20Bolivia%22.
Also want to add, that all objects in JavaScript (arrays are objects too) are stored in memory as links and these links are always not null or zero, that's why Boolean({}) === true, Boolean([]) === true.
Also this is the reason why same objects (copied by value not the link) are always not equal.
{} == {} // false
let a = {};
let b = a; // copying by link
b == a // true
As in JavaScript, everything is an object so for falsy and empty, I use the below condition:
if(value && Object.keys(value).length){
// Not falsy and not empty
}
else{
// falsy or empty array/object
}
I was reading a good book on JavaScript.
It started with:
Boolean type take only two literal values: true and false. These are distinct from numeric values, so true is not equal to 1, and false is not equal to 0.
However, I observed following:
if(1==true)
document.write("oh!!! that's true"); //**this is displayed**
I know, that every type in JavaScript has a Boolean equivalent.
But then, what's the truth?
It's true that true and false don't represent any numerical values in Javascript.
In some languages (e.g. C, VB), the boolean values are defined as actual numerical values, so they are just different names for 1 and 0 (or -1 and 0).
In some other languages (e.g. Pascal, C#), there is a distinct boolean type that is not numerical. It's possible to convert between boolean values and numerical values, but it doesn't happen automatically.
Javascript falls in the category that has a distinct boolean type, but on the other hand Javascript is quite keen to convert values between different data types.
For example, eventhough a number is not a boolean, you can use a numeric value where a boolean value is expected. Using if (1) {...} works just as well as if (true) {...}.
When comparing values, like in your example, there is a difference between the == operator and the === operator. The == equality operator happily converts between types to find a match, so 1 == true evaluates to true because true is converted to 1. The === type equality operator doesn't do type conversions, so 1 === true evaluates to false because the values are of different types.
In JavaScript, == is pronounced "Probably Equals".
What I mean by that is that JavaScript will automatically convert the Boolean into an integer and then attempt to compare the two sides.
For real equality, use the === operator.
Try the strict equality comparison:
if(1 === true)
document.write("oh!!! that's true"); //**this is not displayed**
The == operator does conversion from one type to another, the === operator doesn't.
From the ECMAScript specification, Section 11.9.3 The Abstract Equality Comparison Algorithm:
The comparison x == y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
Thus, in, if (1 == true), true gets coerced to a Number, i.e. Number(true), which results in the value of 1, yielding the final if (1 == 1) which is true.
if (0 == false) is the exact same logic, since Number(false) == 0.
This doesn't happen when you use the strict equals operator === instead:
11.9.6 The Strict Equality Comparison Algorithm
The comparison x === y, where x and y are values, produces true or
false. Such a comparison is performed as follows:
If Type(x) is different from Type(y), return false.
Ah, the dreaded loose comparison operator strikes again. Never use it. Always use strict comparison, === or !== instead.
Bonus fact: 0 == ''
When compare something with Boolean it works like following
Step 1: Convert boolean to Number Number(true) // 1 and Number(false) // 0
Step 2: Compare both sides
boolean == someting
-> Number(boolean) === someting
If compare 1 and 2 with true you will get the following results
true == 1
-> Number(true) === 1
-> 1 === 1
-> true
And
true == 2
-> Number(true) === 1
-> 1 === 2
-> false
Actually every object in javascript resolves to true if it has "a real value" as W3Cschools puts it. That means everything except "", NaN, undefined, null or 0.
Testing a number against a boolean with the == operator indeed is a tad weird, since the boolean gets converted into numerical 1 before comparing, which defies a little bit the logic behind the definition.
This gets even more confusing when you do something like this:
var fred = !!3; // will set fred to true
var joe = !!0; // will set joe to false
alert("fred = "+ fred + ", joe = "+ joe);
not everything in javascript makes a lot of sense ;)
Use === to equate the variables instead of ==.
== checks if the value of the variables is similar
=== checks if the value of the variables and the type of the variables are similar
Notice how
if(0===false) {
document.write("oh!!! that's true");
}
and
if(0==false) {
document.write("oh!!! that's true");
}
give different results
In a way, yes it is 1.
Try these examples in Chrome console:
> 2==true
false
> 1==true
true
> true + 1
2
> true + 2
3
> true + true
2
So, the answer is:
yes, as soon as you use true in any arithmetical context, it's treated as numeric 1, or as Bruce Lee would say, it becomes one. The same way, false is practically zero. But also,
no, if you ask Javascript what it thinks of true, it will say it's a boolean:
> typeof true
'boolean'
It's no surprise in a loosely typed language that sometimes things are not what they are but how you look at them. And if you add true to a string, it will not add 1 but "true" as a string, so at the end of the day, it's by no means equivalent to one. Let me end this with a horrible pun:
true is not a number - but it looks like one
with == you are essentially comparing whether a variable is falsey when comparing to false or truthey when comparing to true. If you use ===, it will compare the exact value of the variables so true will not === 1
I'm wondering what the core difference is between the conditional syntax below?
if (something) {
// do something
}
vs.
if (something == true) {
// do something
}
Are there any differences?
Edit: I apologize. I made a typo when the question was asked. I did not mean to put a triple equals sign. I know that triple equals is a strict operator. I was meaning to ask if '==' is the equivalent of if (something).
The difference is that in if(something), something is evaluated as boolean. It is basically
if(ToBoolean(something))
where ToBoolean is an internal function that is called to convert the argument to a boolean value. You can simulate ToBoolean with a double negation: !!something.
In the second case, both operands are (eventually) converted to numbers first, so you end up with
if(ToNumber(something) == ToNumber(true))
which can lead to very different results. Again, ToNumber is an internal function. It can be simulated (to some degree) using the unary plus operator: +something == +true. In the actual algorithm, something is first passed ToPrimitive if something is an object.
Example:
Assume that
var something = '0'; // or any other number (not 0) / numeric string != 1
if(something) will be true, since '0' is a non-empty string.
if(something == true) will be false, since ToNumber('0') is 0, ToNumber(true) is 1 and 0 == 1 is false.
EDIT: Below only holds true for the original question, in which the === operator was used.
The first one will execute the body of the if-statement if something is "truthy" while the second will only execute it if it is equal in type and value to true.
So, what is "truthy"? To understand that, you need to know what is its opposite: falsey. All values in JavaScript will be coerced into a Boolean value if placed in a conditional expression. Here's a list of falsey values:
false
0 (zero)
"" (empty string)
null
undefined
NaN
All other values are truthy, though I've probably missed some obscure corner case that someone will point out in the comments.
Here's my answer to the updated question:
The conditional if (something) and if (something == true) are equivalent, though the second is redundant. something will be type coerced in the same way in either case. This is wrong. See Felix Kling's answer.
if(something) is equivalent to if(someting == true).
The == operator checks for equality while === checks for sameness. In this case, any truthy value will cause the condition to be met for the first one, but only true will cause the condition to be met for the second one.
EDIT: Felix Kling's answer is correct. Please reference that instead.
Now that the question has changed from === to ==, no, there is no practical difference.
There are a couple ways to look at it. The first example evaluates to see if "something" has a true-like or positive value. So as long as it is not 0, negative, null, or empty it should evaluate the contents of that if statement.
In your second statement you are testing to see if "something" is the equivalent of boolean true. Another words "TRUE" or 1. You could also do a "===" comparison so that it has to be identical to what your comparing it to. So in this case if you did something === true then "something" would have to be boolean true, the value of 1 would not suffice.
There is no difference between the two conditions thing == true and just thing.
There is a large difference between thing === true and just thing, however.
In javascript, values are coerced to a boolean when they are put in a condition. This means all values of all types must be able to be coerced to either true or false. A value that coerces to true is generally called "truthy", and a value that coerces to false is called "falsey".
The "falsey" values are as follows:
NaN (not a number)
'' (empty string)
undefined
null
0 (numeric 0)
Everything else evaluates to true when coerced. This jsFiddle will help you keep track of what is "truthy" and what is "falsey".
The identity operator (===) does NOT perform any type coercion: if the types are different, the comparison immediately fails.