KeyKi
KeyKi

Reputation: 3213

Why `Number(new Boolean(false)) === 0`

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

Answers (4)

FZs
FZs

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

VLAZ
VLAZ

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:

  1. Determine the hint to be "number".
  2. Check if the object implements the @@toPrimitive method.
    • if so, it will call it with the hint ("number")
  3. 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.
  4. 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.
  5. 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.

Upvotes: 1

Spencer Wieczorek
Spencer Wieczorek

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

Jamal Abo
Jamal Abo

Reputation: 472

Because true represents 1

and false represents 0

0 is false 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 and 0.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

1 = false and 0 = true?

Upvotes: 0

Related Questions