admin管理员组

文章数量:1428698

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");
}

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?

Share Improve this question edited Feb 15, 2019 at 23:46 jo_va 14k3 gold badges25 silver badges49 bronze badges asked Feb 15, 2019 at 23:44 Varinder SinghVarinder Singh 1,6001 gold badge11 silver badges27 bronze badges 3
  • @JohnMontgomery Then why statement evaluates to true – Varinder Singh Commented Feb 15, 2019 at 23:48
  • 1 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(). – Madara's Ghost Commented Feb 15, 2019 at 23:53
  • 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. – Chris Tapay Commented Feb 16, 2019 at 0:00
Add a ment  | 

5 Answers 5

Reset to default 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 pare 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");
}

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 parison. 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.

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./2011/02/07/truth-equality-and-javascript/

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 parison (==) 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());

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())

本文标签: nodejsUnderstanding type coercion in JavaScriptStack Overflow