3

I'm new in JavaScript, and I just discovered strange behavior that I can't understand:

var magicVar = Math.sin;
magicVar == true; // it returns false
magicVar === true; // it returns false
if (magicVar) console.log("???"); // it prints "???"

What is happening?

Thank you.

rji89
  • 43
  • 1
  • 6

5 Answers5

4
var magicVar = Math.sin;

From here on magicVar is a reference to the Math.sin function, which is actually an Object (see Function on MDN)

The Function constructor creates a new Function object. In JavaScript every function is actually a Function object.


magicVar == true; // it returns false 

This is false: from the Equality comparison and sameness on MDN if you compare an operand of type Object with an operand of type Boolean using the == operator you always get false (look at the Loose equality using == table).

[EDIT] As Bergi pointed out in the comments you could actually in some cases have objects that loosely compared to a boolean value return true.

What is actually happening behind the scenes is that the comparison algorithm described in ES6 §7.2.12 is applied.

7.2.12 Abstract Equality Comparison

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. ReturnIfAbrupt(x).
  2. ReturnIfAbrupt(y).
  3. If Type(x) is the same as Type(y), then Return the result of performing strict Equality Comparison x === y.
  4. If x is null and y is undefined, return true.
  5. If x is undefined and y is null, return true.
  6. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
  7. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
  8. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
  9. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
  10. If Type(x) is either String, Number, or Symbol and Type(y) is Object, then return the result of the comparison x == ToPrimitive(y).
  11. If Type(x) is Object and Type(y) is either String, Number, or Symbol, then return the result of the comparison ToPrimitive(x) == y.
  12. Return false.

In your case what happens is:

magicVar == true
magicVar == Number(true) // Step 9. x == ToNumber(y).
magicVar == 1
toPrimitive(magicVar) == 1 // Step 11. ToPrimitive(x) == y.
magicVar.toString() == 1
"function sin() { [native code] }" == 1
Number("function sin() { [native code] }") == 1 // Step 7. ToNumber(x) == y.
NaN === 1 // Step 3. x === y.
false

But comparing for example to an object like:

{
     valueOf: function(){
         return 1;
     }
}

you would get:

true == {valueOf(){return 1;}} // it returns true

magicVar === true; // it returns false

This is trivially false, the types of the operands are different and the === operator checks for the operands to have same types and values.


if (magicVar) console.log("???"); // it prints "???"

As all the others answers have said magicVar here is in a Boolean context and gets coerced to true

Andrea Casaccia
  • 4,802
  • 4
  • 29
  • 54
  • Can you anyway explain me this particular choice of design during the development of Javascript language? – rji89 Jul 24 '15 at 10:22
  • 1
    I have to think about it. Anyway generally speaking keep in mind that not all javascript design choices could be optimal. The language has been developed in a very short time and certainly has its flaws. I suggest you this read on the subject https://books.google.ie/books/about/JavaScript.html?id=PXa2bby0oQ0C&source=kp_cover&hl=en – Andrea Casaccia Jul 24 '15 at 10:28
  • @rji89 when you are satisfied with one of the answers, please don't forget to accept one http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Andrea Casaccia Jul 24 '15 at 10:39
  • You are oversimplifying `magicVar == true;`. There are indeed objects that are equal to a boolean, just try out `true == {valueOf(){return 1;}}`. That table on MDN is (was) simply wrong. – Bergi Jul 24 '15 at 12:44
  • 1
    @Bergi that is not an object, it's a code block. If you don't trust MDN look at the standard http://www.ecma-international.org/ecma-262/6.0/index.html 7.2.12 Abstract Equality Comparison, the relevant case is point 12. Is the standard wrong aswell? – Andrea Casaccia Jul 24 '15 at 13:12
  • @AndreaCasaccia: I used a method shorthand (ES6), you might need to try `{valueOf: function(){return 1;}}`. No, the standard is not wrong (I know it well), the table on MDN was (before I fixed it). The relevant points are [ES6 §7.2.12 steps 8 and 9](http://www.ecma-international.org/ecma-262/6.0/index.html#sec-abstract-equality-comparison). – Bergi Jul 24 '15 at 13:16
  • @Bergi I think got your point, you are right. I'll edit my answer to be more precise. – Andrea Casaccia Jul 24 '15 at 13:18
  • @Bergi anyway I wouldn't say that the table is wrong, it covers the Number, String an Boolean cases. The Object case should be considered only when your Object is not a Number, String or Boolean. My citation was oversimplifying indeed. – Andrea Casaccia Jul 24 '15 at 13:27
  • @Bergi No, now I finally understand, the table is actually wrong, If an object is not typeof(Number), but behaves as a Number, the behaviour will not be consistent with that table. – Andrea Casaccia Jul 24 '15 at 13:32
  • 1
    @Bergi take a look at my edit, I hope I got your point. Sorry for the attitude on my first comment but I put quite some effort in writing the answer and I thought it was correct. Feel free to edit if you like. – Andrea Casaccia Jul 24 '15 at 13:49
  • 1
    Thanks for your effort :-) Unfortunately it's still not quite right, as step 9 *is* applied for `Math.sin` before it gets to 12. So `magicVar == true` => `magicVar == 1` => `Number(magicVar) == 1` => `Number(magicVar.toString()) == 1` => `Number("function sin() { [native code] }") == 1` => `NaN == 1` => `false` – Bergi Jul 24 '15 at 14:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84194/discussion-between-andrea-casaccia-and-bergi). – Andrea Casaccia Jul 24 '15 at 14:19
2

magicVar is true as a value. It is true in the sense that it's not empty, it's not null or undefined. So, any non-null value would be a true value. But is this value equal to true ? No. It is true as a boolean not true as a value.

To summarize:

magicVar == true || magicVar === true; // returns false
Boolean(magicVar); // returns true
Amr Ayman
  • 1,129
  • 1
  • 8
  • 24
1

The concept to grasp here is the difference between truthy and falsy values compared to true and false booleans. See here for truthy and here for falsy

Long story short, an if condition passes if the expression is truthy, and magicVar is a function (truthy).

axelduch
  • 10,769
  • 2
  • 31
  • 50
0

magicVar is not equal to true. It is equal to the Math.sin function.

So, in the if statement, it is evaluated to a truthy value (it is defined and does not evaluate to a falsy value).

http://www.sitepoint.com/javascript-truthy-falsy/

G2N
  • 159
  • 1
  • 1
  • 7
0

Comparison function Math.sin with boolean constant return false, because this variables have different types. But when you put not-bool variable to if condition: for example if (Math.sin)... or if (window)... this return true if variable not equal null.

  • 1
    I understand that `magicVar === true` is false because it checks the type, but the `==` operator should perform type juggling, can you explain why `magicVar == true` is false? – Andrea Casaccia Jul 24 '15 at 09:29