isNaN(Number({})) === true
While this is correct, I think you're equating an object with a Boolean
object and the two are not equivalent.
Let's start from the most important thing - Number
converts the argument its given into a numeric. However, it doesn't arbitrarily do that - there are rules about numeric conversion and when it comes to objects, it's not as simple as "all objects are NaN
". Consider this:
const obj0 = {}
const obj1 = {
toString() {
return 1;
}
}
const obj2 = {
toString() {
return 1;
},
valueOf() {
return 2;
}
}
const obj3 = {
toString() {
return 1;
},
valueOf() {
return 2;
},
[Symbol.toPrimitive]() {
return 3;
}
}
const obj4 = Object.create(null);
console.log(Number(obj0)); //NaN
console.log(Number(obj1)); //1
console.log(Number(obj2)); //2
console.log(Number(obj3)); //3
console.log(Number(obj4)); //Error
Not all objects are equal when converting to a number. Some happen to be even more unequal than others.
When Number
is given an object, it goes through the process to convert it to a primitive with a preference (hint) for a number. To do this, it will go through the following steps:
- Determine the hint to be "number".
- Check if the object implements the
@@toPrimitive
method.
- if so, it will call it with the hint ("number")
- If that doesn't exist it will then look for a
valueOf
method.
- this is done because the hint is "number", so
valueOf
will be checked first.
- If that doesn't exist, then it will check for a
toString
method
- again, this is based on the hint being "number". If the hint was "string", the last two steps would be reversed.
- If that doesn't exist, then raise an error.
Once an appropriate method has been found, it's executed and the value returned will be transformed into numeric.
We haven't touched Boolean
yet - this is just how the generic Number
does the conversion. So, in summary - an object can be converted to a primitive number, if it implements the correct functionality to do so.
Boolean
objects do implement the correct functionality - they have a valueOf
method that returns the primitive boolean they hold:
const T1 = new Boolean(true);
const T2 = new Boolean(true);
console.log("T1.valueOf()", T1.valueOf());
console.log("typeof T1.valueOf()", typeof T1.valueOf());
console.log("T1 === T2", T1 === T2);
console.log("T1.valueOf() === T2.valueOf()", T1.valueOf() === T2.valueOf());
So, in that case:
Number(new Boolean(true))
= Number(new Boolean(true).valueOf())
= Number(true)
And if we generalise it a bit, then: Number(new Boolean(bool))
= Number(bool)
From the ToNumber
conversion we know that true
is turned into 1
while false
is turned into 0
. Thus the equality Number(new Boolean(false)) === 0
makes perfect sense, since Number(false)
is indeed 0
. Same with Number(new Boolean(true)) === 1
.