28

I had an interesting interview question today that stumped me a little. I was asked about falsey values. So undefined, NaN, null, 0, and an empty string all evaluate to false. What is the reason this is useful to know in JavaScript? The only thing I can think of is instead of having to do this:

if (mystring === '' || mystring === undefined) { }

I can do this:

if (!mystring)

Is this the only useful application?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mike Rifgin
  • 10,409
  • 21
  • 75
  • 111
  • 10
    NaN instead of NAn, null instead of Null (JavaScript is case-sensitive) – Šime Vidas Oct 20 '10 at 22:10
  • 1
    One of the things you have to love about programming is having to keep up with (english) language terms. is "falsey" really a legitimate programming term, or does it just mean "false values"? If it is a -real- term, and not just geek speak, where is a url defining it, as I can't seem to find a legitimate definition of the term. – Bill Oct 20 '10 at 22:10
  • @Bill I guess "truthy" and "falsy" are neologisms then ... http://javascript.crockford.com/style2.html – Šime Vidas Oct 20 '10 at 22:13
  • @bill...to be honest yesterday was the first time i'd heard it..the person who I was interviewed by referred to it. We also talked about Douglas Crockford so he may have got the terms from there. – Mike Rifgin Oct 21 '10 at 10:18
  • related: Truthy string values http://stackoverflow.com/a/5515349/759452 – Adriano Mar 17 '14 at 08:40

6 Answers6

27

One dangerous issue of falsey values you have to be aware of is when checking the presence of a certain property.

Suppose you want to test for the availability of a new property; when this property can actually have a value of 0 or "", you can't simply check for its availability using

if (!someObject.someProperty)
    /* incorrectly assume that someProperty is unavailable */

In this case, you must check for it being really present or not:

if (typeof someObject.someProperty == "undefined")
    /* now it's really not available */

Also be aware that NaN isn't equal to anything, even not to itself (NaN != NaN).

Marcel Korpel
  • 21,536
  • 6
  • 60
  • 80
  • 1
    But you can legitimately set a property to undefined, thus breaking this test. It's almost certainly better to use someObject.hasOwnProperty, and to recursively check this if you actually care if the property exists anywhere in the objects prototype chain. – Angiosperm Oct 20 '10 at 23:39
  • @Angiosperm In JavaScript, object are dynamic anyway, so there is no practical difference between an object not having a property and an object having a property set to `undefined` – Šime Vidas Oct 20 '10 at 23:57
  • @Šime Vidas Scenario: our application calls out to some remote location to check the existence of a resource. The resource's existence is constant during the app's lifecycle. This checking can be expensive, so we want to start caching the call's result. Lets do that be setting some property of an object to the result of that call. The existing code simply checks if the result of the call is 'undefined' to decide if the resource exists. To not have to change our current interface, the cache mechanism would have to check if the appropriate property actually exists, rather than is just undefined. – Angiosperm Oct 21 '10 at 01:10
  • @Angiosperm: Please bare in mind that I'm checking the `typeof` a property, not its value. – Marcel Korpel Oct 21 '10 at 10:21
  • @Angiosperm In your scenario, I would set up the program to set `null` if the resource check returns `undefined`. Can you cite a relevant source that recommends `foo.hasOwnProperty` in favor of `typeof foo == "undefined"`? – Šime Vidas Oct 21 '10 at 10:55
  • @Šime Vidas I got nothin. @Marcel Korpel are there other values for which typeof returns "undefined"? – Angiosperm Oct 21 '10 at 18:28
  • @Angiosperm: Not that I know of, but I've just moved and can't look for it extensibly at the moment. – Marcel Korpel Oct 23 '10 at 14:48
  • 2
    The typeof check is unnecessary. If you want to check that a property exists, you'll usually want to know if it's either undefined or null. For that check do if (someObject.someProperty == null). If you only want to check if it's undefined do if (someObject.someProperty === undefined). – kybernetikos Sep 09 '11 at 11:18
  • 4
    @Adam: one drawback: `undefined` *might* be overwritten. Or use the `in` operator: `if ("property" in object)` – Marcel Korpel Sep 15 '11 at 16:49
  • typeof null is "object" so using typeof might not be full proof – Rishul Matta Nov 03 '14 at 05:06
8

There are two separate issues with 'falsey' values in JavaScript.

Firstly there is the official conversion scheme, which is what is returned by Boolean(x). This returns false when x is false or 0 or NaN or null or undefined or "" and true otherwise. This is the same behaviour as the

if (condition) {/*true path*/} else {/*false path*/}

that is, the false path is executed if Boolean(condition) would have returned false and the true path is executed otherwise. This behaviour is often used to check to see if a property is defined. However, doing that is not safe unless you are certain that the property would be an object or an array if it is defined. The safest way to test if a property is defined is to do

if (property != null) { /*property is defined*/} 

which makes sure that the property is not null or undefined. If you only want to make sure the property is not undefined do

if (property !== undefined) { /*property is not undefined (but may be null)*/ } 

(notice the extra = in !==).

Secondly, there are all the values that == false. This is everything that can be coerced to 0 (which is what false gets coerced to). This includes all the values that convert to false except NaN (which can't == false by virtue of it never == anything), null and undefined. But it also includes all objects that when converted to a string and then converted to a number are equal to 0. For example, this includes everything that when converted to a string is either the empty string "" or "0" or "-0" or "+0" or "0x00" or "000" or "0e0" or "0.0000"...., for example,

({toString: function() {return "-00.0e000";}}) == false

is true. Interestingly, this includes the empty array, and any nesting of arrays containing only a single other item that returns an empty or 0 string since arrays rendered as strings show only the contents without the surrounding brackets. That is,

[[[[0]]]] == false; // Because [[[[0]]]].toString() === "0"
[] == false;
[[[""]]] == false;
["0"] == false;
[[({toString: function() {return "0";}})]] == false;

The full algorithm for calculating == false is described here.

The reason this matters is because it can lead to subtle, difficult to find bugs if you don't understand most of these rules. Most important takeaways are probably how the if (condition) works and that using === avoids most of the other crazy stuff.

kybernetikos
  • 8,281
  • 1
  • 46
  • 54
5

It's important to understand how this works in JS, so you're not surprised. Not necessarily just what is falsey, but what is truthy and how they compare to each other.

One example is that '0' is considered equal to 0 with ==, but it is not equal to '' - though 0 is. JavaScript comparison isn't always transitive.

So this means that just because (foo==bar && bar==fizz) is true, (foo==fizz) is not always true. To go with the above example, '0'==0, and 0=='', but '0'!='' - because you're comparing strings in the latter instance, so they are compared as strings and not coerced to numbers.

kybernetikos
  • 8,281
  • 1
  • 46
  • 54
JAL
  • 21,295
  • 1
  • 48
  • 66
3

It's useful to detect if a browser is has specific predefined objects:

if(!!navigator.geolocation){
  // executes if the browser has geolocation support
}

if(!!document.createElement('canvas').getContext){
  // executes if the browser supports <canvas>
}

Explanation: navigator.geolocation is an object or undefined. In the case it's an object !navigator.geolocation will return false, if it's undefined it'll return true. So, to check if a browser has geolocation enabled, you want to 'flip' the boolean once more, by adding another !.

Harmen
  • 22,092
  • 4
  • 54
  • 76
  • So if I did if(!navigator.geolocation){ } and it's undefined then this would return false? – Mike Rifgin Oct 20 '10 at 22:07
  • 1
    I don't get it... What's the difference between `if (!!foo.bar)` and `if (foo.bar)`? – Šime Vidas Oct 20 '10 at 22:08
  • @elduderino No, it would return true. The ! operator first converts its operand to a boolean value and then switches it... In the case ther navigator.geolocation is undefined, it will be converted to the boolean value false, and then switched to true... – Šime Vidas Oct 20 '10 at 22:17
  • @Šime Vidas: I've got these snippets from the Modernizr source. I think they use it too make absolutely sure they're dealing with a boolean. But I actually don't see a situation when there's difference between `if (!!foo.bar)` and `if (foo.bar)` neither... – Harmen Oct 20 '10 at 22:18
  • @Harmen I believe `!!` is not necessary since JavaScript has automatic type coercion. The expression in the header of if statements will automatically get converted to boolean, so you don't have to use `!!` do convert it explicitly to a boolean value... – Šime Vidas Oct 20 '10 at 22:19
  • @Šime Vidas - oh yeah of course it would. I also do not see the difference of using if (!!foo.bar) and if (foo.bar) – Mike Rifgin Oct 21 '10 at 12:29
  • 2
    In this case, there isn't any. The `!!` operators are used for typecasting into boolean, so if you want to explicitly convert a value to boolean, you use `!!value`. – Šime Vidas Oct 21 '10 at 13:34
  • 2
    Probably better to explicitly typecast into a boolean with Boolean(value). It's significantly more readable and not that many more characters. – kybernetikos Dec 22 '11 at 01:13
3

It is important to know that 0 evaluates to false to prevent doing things like:

if(str.indexOf('foo'))
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • How would that work anyway? It returns -1 when nothing is found, which is not a falsy value.. – Nick Russler Dec 11 '13 at 14:32
  • @FelixKling: But it is not important to know that 0 evaluates to false in this case. When -1 would evaluate to false, then the fact that 0 also evaluates to false but does not indicate that nothing was found would be a stumbling block. – Nick Russler Dec 11 '13 at 16:26
  • 1
    @Nick: I think that it's important to know both, that `-1` is truthy and `0` is falsy. I probably haven't thought about the `-1` case back then. In PHP it would be more severe, since there the equivalent function returns `false` if the string wasn't found. – Felix Kling Dec 11 '13 at 16:34
  • 1
    @FelixKling That makes sense. Btw. `if(str.indexOf('foo') + 1)` should work like expexted (in JS) but would be not very readable.. – Nick Russler Dec 11 '13 at 16:47
3

They're also useful for setting default values...

function foo(bar){
    alert(bar || "default");
}

I know a lot of people try to do

if (typeof(foo) === "undefined"){}

to get around falsiness, but that's got its own problems because

typeof(null) === "object"

for some reason

T J
  • 42,762
  • 13
  • 83
  • 138
Mike Ruhlin
  • 3,546
  • 2
  • 21
  • 31
  • Yeah I knew that about null. Weird. Good examples. Thanks – Mike Rifgin Oct 20 '10 at 22:06
  • @elduderine a nastier thing about null is isNaN(null) === false. – Angiosperm Oct 20 '10 at 23:34
  • Your (bar || "default") example is probably an antipattern. This is because it will trigger on the empty string which the user of your function may have intended to be the value of bar (I've come across this bug a number of times in libraries). Even if the context means that you understood this, it won't be clear to the user of your function that this is the case without a comment. Best to avoid this style completely for values that may be strings (""), numbers (NaN) or booleans (false). – kybernetikos Dec 22 '11 at 01:04