JavaScript: Hitting Bottom #3 – The Crucible of Truthiness

Some programming languages judge truth by the nature of non-zero values (C); some by non-false, non-nil values (Ruby). JavaScript follows it’s gut. If it seems true it’s usually true, if it seems false it’s usually false… usually.

There are two kinds of truth in JavaScript, things that take the `if` branch in `if-else` expressions; and things that == false.

Let’s start with things that == false:

    test("false idols", function() {
      equals(0 == false, true);
      equals('' == false, true);
      equals(' ' == false, true);
      equals('0' == false, true);
      equals([] == false, true);
 
      equals(null == false, false, "!");
      equals(undefined == false, false, "!");
    });

The first thing to note is that empty strings and strings that can be converted to the integer zero are == to false. The second thing to note is that `null` and `undefined` are not == to false. A lot of things in JavaScript == false, actually infinitely many. A lot of different arrays for example:

    test("false Arrays", function() {
      equals([0] == false, true);
      equals([''] == false, true);
      equals([' '] == false, true);
      equals(['0'] == false, true);
      equals([[]] == false, true);
      equals([false] != false, true, "!!! The `toString()` is 'false'");
      equals([null] == false, true);
      equals([undefined] == false, true);
 
      // It goes on like that, the toString ends up as '0'
      equals([[[[[[[[[0]]]]]]]]] == false, true);
 
      // This adds weight to the toString hypothesis
      equals([{toString: function() {return '';}}] == false, true);
      equals([{toString: function() {return '0';}}] == false, true);
    });

Some Objects with particular `toString` methods also == false:

    test("Objects with toString methods defined that are equivalent to false", function() {
      equals({toString: function(){return false}} == false, true, "!!");
      equals({toString: function(){return null;}} == false, true, "!!");
      equals({toString: function(){return '';}} == false, true, "!!");
      equals({toString: function(){return '0'}} == false, true, "!!");
      equals({toString: function(){return 'false'}} != false, true, "!!");
      equals({toString: function(){return undefined}} != false, true, "!!");
    });

Also, as mentioned previously, any strings that convert to the number zero such as:

    test("false Strings", function() {
      equals('                        ' == false, true);
      equals('            0.          ' == false, true);
      equals('0.0000000000000000000000' == false, true);
    });

Sounds like it would be hard to keep track of everything that evaluates to false… but don’t worry it has no effect on if-else statements. For if-else statements only things that are cast to the primitive `false` by Boolean matter. Wouldn’t Boolean cast everything that == false to be `false`? Not on your life!

    test("Boolean Goolean", function() {
      equals(Boolean(false) == false, true);
      equals(Boolean(0) == false, true);
      equals(Boolean('') == false, true);
      equals(Boolean(null) == false, true, "!!");
      equals(Boolean(undefined) == false, true, "!!");
      equals(Boolean(NaN) == false, true, "!!");
      equals(Boolean(' ') != false, true, "!!");
      equals(Boolean('0') != false, true, "!!");
      equals(Boolean([]) != false, true, "!!");
      equals(Boolean(new Boolean(false)) == true, true, "!!!");
    });

The exclamations are included for the ones that == false is different for. The only six things that evaluate to false in an if expression are: false, 0, null, undefined, NaN, and ”. Few enough to count on one hand! Aside from Boolean casting things that == false to `true` and casting things that != false to `false`, the one big thing to watch out for is that all Boolean objects are cast to `true` especially `new Boolean(false)` so don’t use it in your if statements!

Here’s a long boring series of tests to illustrate that the if-else branching does indeed match how Boolean casts things and not whether or not they == false. Exclamations where it’ll getcha. I’ll leave it as an exercise for the reader to skim to the bottom, say “hmmm…..” and then start browsing Reddit (or Hacker News).

    test("if statements", function() {
      var x;
      var ifX;
 
      x = undefined;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!!");
 
      x = null;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!!");
 
      x = false;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
 
      x = true;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true)
 
      x = 0;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
 
      x = NaN;
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!!");
 
      x = '';
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, false);
 
      x = ' ';
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true);
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, false, "!!");
 
      x = '0';
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!");
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, false, "!!");
 
      x = [];
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!");
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, false, "!!");
 
      x = {};
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true);
 
      x = {toString: function(){return '';}};
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true);
 
      x = new Boolean(false);
      if(x) { ifX = true; } else { ifX = false; }
      equals(ifX, true, "!!!")
      if(x != false) { ifX = true; } else { ifX = false; }
      equals(ifX, false, "!")
    });

Leave a Reply

Your email address will not be published. Required fields are marked *