Understanding type coercion in JavaScript
Asked Answered
B

5

5

I know == operator performs the type coercion. But I can't understand the below behaviour.

const x = new Boolean(false);

if (x) {
  console.log("if(x) is true");
}

if (x == false) {
  console.log("if(x == false) is true");
}

Surprisingly, above snippet prints both lines:

if(x) is true if(x == false) is true

Can someone explain this weird behaviour or there is something fundamental I'm missing?

Bracketing answered 15/2, 2019 at 23:44 Comment(3)
@JohnMontgomery Then why statement evaluates to trueBracketing
This isn't a type coercion thing, this is a boxing thing. This is exactly why you don't do new Boolean() or new Number() or new String().Minnow
Please refer to the following documentation from the well-versed Kyle Simpson about Falsy Objects. I actually suggest you read the whole book that is there for free.Hendry
C
4

As mentioned by other answers, that's because x is an Object – a Boolean object, but still an object, since you're using the new operator – and is coerced only when you compare x to false: the if (x) is checking if x is a truthy value, and therefore doesn't need coercion (there are no other operands involved): an object is always "true" (weeeell… almost always: typeof null returns object but it's a falsy value. But that's another story…).

You can easily checking when the coercion is invoked tapping the toPrimitive symbol:

var x = new Boolean(false);

// first of all, if it wasn't an object you couldn't
// do this
x[Symbol.toPrimitive] = function(hint) {
  console.log({hint});
  return this.valueOf();
}

// no console.log yet
if (x) {
  console.log("if(x) is true");
}

// here you got the console.log before the one
// inside the block, since the coercion happens
// in the `if`
if (x == false) {
  console.log("if(x == false) is true");
}
Celinecelinka answered 16/2, 2019 at 0:1 Comment(2)
I'm still trying to understand it. If x is truthy value coercion should convert it to true and thence, x == false should be false in second if statement, but that's not the caseBracketing
I think you're missing the foundation of coercion: it happens when you compare two things: you need two operands. if (x) doesn't compare x with anything: it just check that x is a truthy value – attention! "truthy" not "equals to true", and "truthy" is not a type per se, hence no coercion. When you do x == false, you're comparing two things, and since you're using the abstract equality (==) the coercion is performed.Celinecelinka
L
1

You should be using Boolean(false) instead of new Boolean(false), since Boolean is a function.

Otherwise you get an empty object {}, which is not the same type as what is returned by the function itself, which is a boolean.

const x = new Boolean(false);
const y = Boolean(false);

console.log(x, typeof x);
console.log(y, typeof y);

In the your first test, you only check if the value is truthy, and an empty object is truthy, since x = {}, the test passes:

const x = new Boolean(false);

console.log(x, !!x, !!{}, Boolean(x))

if (x) {
  console.log("if(x) is true");
}

However, when using ==, the operator coerces new Boolean(false) to its primitive value using x.valueOf which is false and thus the equality passes.

const x = new Boolean(false);

console.log(x.valueOf())
Lyrebird answered 15/2, 2019 at 23:49 Comment(0)
S
1

new Boolean(false) produces an object. Objects are always truthy even if they wrap a falsy primitive value. For example, new String("") is also truthy despite "" being falsy.

On the other hand, when you do new Boolean(false) == false, it coerces the object to its primitive value for the comparison. Incidentally, new Boolean(false) === false is not true, since their types don't match.

As a general rule, you shouldn't use object constructors for primitive types unless you have a specific reason for it, to avoid unexpected behavior like this.

Switzer answered 15/2, 2019 at 23:51 Comment(0)
R
1

If you write

const x = new Boolean(false);

typeof x will return object. The type object is "truthy", which means it evaluates to true if there's no operator like ==. However, the value of it is false, which is why the second statement evaluates to true as well.

So the if statements behave differently, because the if without operator checks whether the type is truthy or falsy (in this case truthy -> true) and the if with the comparison (==) calls .valueOf() which is false.

You shouldn't be using new wrappers for this scenario anyway.

const x = false;

is enough. For casting, you can use Boolean() without new wrapper.

To check whether a value is truthy, you can use a double negation:

const x = new Boolean(false);

if (x) console.log(!!x);

if (x == false) console.log(x.valueOf());
Rely answered 15/2, 2019 at 23:52 Comment(0)
R
1

when you do if (expression) in javascript the expression is evaluated by being cast to a boolean.

Somewhat confusingly, Boolean(new Boolean(false)) evaluates to true because as Nick said it is still an object. This is what is causing the behaviour you're confused about.

Good read for more info https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/

Russell answered 15/2, 2019 at 23:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.