Reputation: 3213
Boolean(new Boolean(...)) === true
because new Boolean(...)
is an object.
But why Number(new Boolean(false)) === 0
(+new Boolean(false) === 0
) and Number(new Boolean(true)) === 1
? Why not NaN
*?
Why in the first example there is no unboxing, but in the second case there is it?
*isNaN(Number({})) === true
Upvotes: 3
Views: 317
Reputation: 18619
Boolean objects have a valueOf
method, and it can be used to customize the primitive value of the object in type conversions.
Boolean#valueOf()
returns true
for new Boolean(true)
and false
for new Boolean(false)
.
This method is internally called by both the Number
function and the unary plus (+
) operator, so the code becomes to:
Number(true)
which is equal to 1
, as true
has the numeric value of 1.
You can also implement a valueOf
function on any object, to make it have a custom value, for example:
const object={
valueOf(){
return 10
}
}
console.log(Number(object)) //10
Upvotes: 1
Reputation: 28977
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:
@@toPrimitive
method.
valueOf
method.
valueOf
will be checked first.toString
method
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
.
Upvotes: 1
Reputation: 21565
As @ASDFGerte mentioned. This is because the ToNumber()
method which is called by the Number()
constructor will call .ToPrimitive()
on the argument if an object is passed. This is why it's treated as a Boolean primitive rather than an object.
Upvotes: 2
Reputation: 472
Because true
represents 1
and false
represents 0
0
isfalse
because they’re both zero elements in common [semirings][Semiring on Wikipedia]. Even though they are distinct data types, it makes intuitive sense to convert between them because they belong to isomorphic algebraic structures.
0
is the identity for addition and zero for multiplication. This is true for integers and rationals, but not IEEE-754 floating-point numbers:0.0 * NaN = NaN
and0.0 * Infinity = NaN
.
false
is the identity for Boolean xor (⊻) and zero for Boolean and (∧). If Booleans are represented as {0, 1}—the set of integers modulo 2—you can think of ⊻ as addition without carry and ∧ as multiplication.
""
and[]
are identity for concatenation, but there are several operations for which they make sense as zero. Repetition is one, but repetition and concatenation do not distribute, so these operations don’t form a semiring.Such implicit conversions are helpful in small programs, but in the large can make programs more difficult to reason about. Just one of the many tradeoffs in language design.
[Semiring on Wikipedia]: http://en.wikipedia.org/wiki/Semiring
quote from
read this
Upvotes: 0