Why is "" == [null] true in JavaScript? - javascript

I know JavaScript has lots of insane results with comparisons between types, though I don't fully understand why. Came across this one today.
Why does
"" == [null]
evaluate to true in JavaScript?
Some more Javascript equality amusement, thanks to #Qantas:
Why does 2 == [2] in JavaScript?
Why is 0 == "" true in JavaScript
Why if([]) is validated while [] == false in javascript?
Why does !{}[true] evaluate to true in JavaScript?

The "Abstract Equality Comparison Algorithm" has many parts, but the important one here is this:
If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).
(There's a mirror-image of that too.) So, because "" is a string and [null] is an object, we've got to first convert [null] to a string by calling ToPrimitive([null]). That's an internal operation described as follows, when it's asked to convert an Object instance to a primitive value:
Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.
Now, the [[DefaultValue]] internal operation will call .toString() on the object and return that value. Try [null].toString() in your browser console:
> [null].toString()
""
And there you have it.
Edit: And why is [null].toString() an empty string? Because the .toString() operation on Array instances always just calls .join(), and that always yields an empty string for null and undefined values. Thus an array of one null ends up as just a single empty string.

It's according to the arcane type-conversion rules of Javascript. Rule #8:
If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
So the comparison is between x = "" and y = [null] converted to a string using ToPrimitive. Converting an array with one null element results in an empty string (because Array.toString() returns a comma-separated list of values), hence they evaluate to equal.

Why does "" == [null] evaluate to true?
Because you're comparing an array with a string, using the non-strict equality operator == - so it will try to cast values to the same type before comparing them.
What happens in detail is:
you compare a string to an object, so the object is cast to a string:
When an array is cast to a primitive value, it's .toString() method is invoked (as explained in detail by the other answers), which is equivalent to calling .join():
which in case of a one-element array that only contains an undefined or null value returns the empty string
which finally is equivalent to the empty string
This third step is the unexpected one ([null]+"" != null+""), if it actually did cast that to a string the result would have been "null" and your equality be false.

Let's look at the spec and follow through each step
Going via the Abstract Equality Comparison Algorithm (§11.9.3):
typeof ""; // string and typeof [null]; // object so not applicable
neither is null or undefined so not applicable
same as 2
neither is a number, not applicable
same as 4
neither is a bool, not applicable
again not applicable
finally, something applicable, now we need to know ToPrimitive([null])
§9.1 ToPrimitive for Objects says we need to work out [[DefaultValue]] (§8.12.8), points 1 and 2 of which say if you can do .toString and it gives a string, return that, so
[null].toString(); // ""
So we are now performing the comparison "" == "" which is true by the Abstract Equality Comparison Algorithm's point 1. d.
If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.

JavaScript is weakly typed; you can use the following to get a false result:
"" === [null]

The value null is a JavaScript literal representing null or an "empty" value, i.e. no object value is present. It is one of JavaScript's primitive values.
The value null is a literal (not a property of the global object like undefined can be). In APIs, null is often retrieved in place where an object can be expected but no object is relevant. When checking for null or undefined beware of the differences between equality (==) and identity (===) operators (type-conversion is performed with the former).
typeof null // object (bug in ECMAScript, should be null)
typeof undefined // undefined
null === undefined // false
null == undefined // true

Related

Why does an empty filter act as a Boolean? [duplicate]

What are the values in JavaScript that are 'falsey', meaning that they evaluate as false in expressions like if(value), value ? and !value?
There are some discussions of the purpose of falsey values on Stack Overflow already, but no exhaustive complete answer listing what all the falsey values are.
I couldn't find any complete list on MDN JavaScript Reference, and I was surprised to find that the top results when looking for a complete, authoritative list of falsey values in JavaScript were blog articles, some of which had obvious omissions (for example, NaN), and none of which had a format like Stack Overflow's where comments or alternative answers could be added to point out quirks, surprises, omissions, mistakes or caveats. So, it seemed to make sense to make one.
Falsey values in JavaScript
false
Zero of Number type: 0 and also -0, 0.0, and hex form 0x0 (thanks RBT)
Zero of BigInt type: 0n and 0x0n (new in 2020, thanks GetMeARemoteJob)
"", '' and `` - strings of length 0
null
undefined
NaN
document.all (in HTML browsers only)
This is a weird one. document.all is a falsey object, with typeof as undefined. It was a Microsoft-proprietory function in IE before IE11, and was added to the HTML spec as a "willful violation of the JavaScript specification" so that sites written for IE wouldn't break on trying to access, for example, document.all.something; it's falsy because if (document.all) used to be a popular way to detect IE, before conditional comments. See Why is document.all falsy? for details
"Falsey" simply means that JavaScript's internal ToBoolean function returns false. ToBoolean underlies !value, value ? ... : ...; and if (value). Here's its official specification (2020 working draft) (the only changes since the very first ECMAscript specification in 1997 are the addition of ES6's Symbols, which are always truthy, and BigInt, mentioned above:
Argument type
Result
Undefined
Return false.
Null
Return false.
Boolean
Return argument.
Number
If argument is +0, -0, or NaN, return false; otherwise return true.
String
If argument is the empty String (its length is zero), return false; otherwise return true.
BigInt
If argument is 0n, return false; otherwise return true.
Symbol
Return true.
Object
Return true.
Comparisons with == (loose equality)
It's worth talking about falsy values' loose comparisons with ==, which uses ToNumber() and can cause some confusion due to the underlying differences. They effectively form three groups:
false, 0, -0, "", '' all match each other with ==
e.g. false == "", '' == 0 and therefore 4/2 - 2 == 'some string'.slice(11);
null, undefined match with ==
e.g. null == undefined but undefined != false
It's also worth mentioning that while typeof null returns 'object', null is not an object, this is a longstanding bug/quirk that was not fixed in order to maintain compatibility. It's not a true object, and objects are truthy (except for that "wilful violation" document.all when Javascript is implemented in HTML)
NaN doesn't match anything, with == or ===, not even itself
e.g. NaN != NaN, NaN !== NaN, NaN != false, NaN != null
With "strict equality" (===), there are no such groupings. Only false === false.
This is one of the reasons why many developers and many style guides (e.g. standardjs) prefer === and almost never use ==.
Truthy values that actually == false
"Truthy" simply means that JavaScript's internal ToBoolean function returns true. A quirk of Javascript to be aware of (and another good reason to prefer === over ==): it is possible for a value to be truthy (ToBoolean returns true), but also == false.
You might think if (value && value == false) alert('Huh?') is a logical impossibility that couldn't happen, but it will, for:
"0" and '0' - they're non-empty strings, which are truthy, but Javascript's == matches numbers with equivalent strings (e.g. 42 == "42"). Since 0 == false, if "0" == 0, "0" == false.
new Number(0) and new Boolean(false) - they're objects, which are truthy, but == sees their values, which == false.
0 .toExponential(); - an object with a numerical value equivalent to 0
Any similar constructions that give you a false-equaling value wrapped in a type that is truthy
[], [[]] and [0] (thanks cloudfeet for the JavaScript Equality Table link)
Some more truthy values
These are just a few values that some people might expect to be falsey, but are actually truthy.
-1 and all non-zero negative numbers
' ', " ", "false", 'null'... all non-empty strings, including strings that are just whitespace
Anything from typeof, which always returns a non-empty string, for example:
typeof null (returns a string 'object' due to a longstanding bug/quirk)
typeof undefined (returns a string 'undefined')
Any object (except that "wilful violation" document.all in browsers). Remember that null isn't really an object, despite typeof suggesting otherwise. Examples:
{}
[]
function(){} or () => {} (any function, including empty functions)
Error and any instance of Error
Any regular expression
Anything created with new (including new Number(0) and new Boolean(false))
Any Symbol
true, 1, "1" and [1] return true when compared to each other with ==.
Don't forget about the non-empty string "false" which evaluates to true
Just to add to #user568458's list of falsy values:
In addition to integer number 0, the decimal number 0.0, 0.00 or any such zeroish number is also a falsy value.
var myNum = 0.0;
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet prints I am a falsy value
Similarly hex representation of the number 0 is also a falsy value as shown in below code snippet:
var myNum = 0x0; //hex representation of 0
if(myNum){
console.log('I am a truthy value');
}
else {
console.log('I am a falsy value');
}
Above code snippet again prints I am a falsy value.
Addition to the topic, as of ES2020 we have a new value which is falsy, it's BigInt zero (0n):
0n == false // true
-0n == false // true
0n === false // false
-0n === false // false
So with this, we now have 7 "falsy" values in total (not including document.all as mentioned by user above since it's part of DOM and not JS).

Is there an operator for comparing undefined or null types?

Sorry if the title made it unclear, but I've been wondering, is there an operator for comparing types like null and "null"?
We all know that:
"1" == 1 returns true.
and
"1" === 1 returns false.
But when I try to do something like:
undefined == "undefined", for me, it returns false, even though I am not using ===.
Why does this occur? Is there an operator for comparing undefined and "undefined", or null and "null"?, etc...
In answer to the question in the title, no there isn't - JavaScript does not generally examine the semantic content of strings - "use strict" placed at the beginning of code to invoke strict mode execution is the exeception.
Note that the typeof operator is a convenience operator which does not return the data type of its operand in all cases - function objects are of (JavaScript) data type "Object", and null is of (JavaScript) data type "Null".
"undefined" is a string value with specific content. It is not equal to undefined (the one and only value with data type "Undefined") or null (the one and only value with data type "Null").
There is however an automatic type conversion between null and undefined which causes the non-strict equality operator to treat them as being equal, often used with a negation operator:
if( value != null) {
// proceed knowing value isn't `undefined` or `null
}

why 3==new Number(3) gives true why?

I follow the below links
Why should you not use Number as a constructor?
Question about object.method in JavaScript
why 3==new Number(3) gives true why ??
3== new Number(3) // true
As of I know == only check the value.but new Number(3) is a object how it value become 3.
how new Number(3) value is 3
Abstract Equality Comparison, or x == y, does, on step 10:
If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
So the evaluation of
3 == new Number(3)
becomes
3 == Number(new Number(3))
Although new Number(3) results in a (number) object, it then gets cast to its primitive value (a plain non-object number), and 3 == 3 is true.
It's giving true because of coercion in javascript.
Javascript will convert object to number implicitly while evaluating equality operation.
While it's true that == coerces the data type for comparison to be done, your basic question of:
As of I know == only check the value.but new Number(3) is a object how
it value become 3.
has a different answer. All objects in JavaScript inherit from Object.prototype and that object has a valueOf() and a toString() method. These methods are automatically used by the JavaScript runtime when the fundamental (primitive) value or string representation of that value are required. So in this case, although new Number(3) returns an object, the valueOf() method is implicitly being called to return the value of 3 for the rest of the expression to work with.
From the MDN link above:
JavaScript calls the valueOf method to convert an object to a
primitive value. You rarely need to invoke the valueOf method
yourself; JavaScript automatically invokes it when encountering an
object where a primitive value is expected.
These methods are automatically called when needed, as I said, but you can call them as well on any object:
// There will be no implicit call for .valueOf here because there is no
// context for the JS runtime to know what you want to do with the object.
// Instead, you get {}, which means Object
console.log(new Number(3)); // {}
// But, you can get the most basic value if you want:
console.log(new Number(3).valueOf()); // 3

Why do empty JavaScript arrays evaluate to true in conditional structures?

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
}

Is empty string treated as falsy in javascript?

I've noticed that if you have a statement as the following:
var test = "" || null
test will evaluate to null but if we do something like the following:
var test = "test" || null
test will evaluate to "test", the same holds true for any object in place of the string, so does javascript treat empty string as either a falsy or null value, and if so why? Isn't an empty string still an object, so shouldn't it be handled the same?
I've tested this out in FireFox, Chrome, IE7/8/9, and Node.
Does javascript treat empty string as either a falsy or null value, and if so why?
Yes it does, and because the spec says so (§9.2).
Isn't an empty string still an object
No. An primitive string value is no object, only a new String("") would be (and would be truthy)
String is not an object, it's a primitive like number or boolean.
The empty string, NaN, +0, -0, false, undefined and null are the only values which evaluate to false in direct boolean conversion.
A string isn't an object in JS. Other "falsy" values are: 0, NaN, null, undefined.
One dangerous issue of falsey values you have to be aware of is when checking the presence of a certain property.
Suppose you want to test for the availability of a new property; when this property can actually have a value of 0 or "", you can't simply check for its availability using
if (!someObject.someProperty)
/* incorrectly assume that someProperty is unavailable */
In this case, you must check for it being really present or not:
if (typeof someObject.someProperty == "undefined")
/* now it's really not available */
SEE HERE
Yes an empty string is falsy, however new String("") is not.
Note also that it's well possible that
if (x) { ... }
is verified, but that
if (x == false) { ... }
is verified too (this happens for example with an empty array [] or with new String("")).

Categories

Resources