Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2014 (Bloomington, MN) with:

Javascript's Implicit Boolean Conversions

By Ben Nadel on

In ColdFusion, I am very confident about what values will be implicitly converted to true / false boolean values. In Javascript, however, my confidence is much lower. I know that objects will be false if they are "null", but what about things like numeric values? I end up writing code like this:

  • if (strValue.length > 0){ ... }

... because I'm never sure how "strValue.length" will be used without explicit comparisons. This not only demonstrates a lack of understanding in the language, it also means excess code and a lower signal-to-noise ratio. Shame on me!

Well, not no more! Now, I am finally testing all of these values to check the implicit boolean value conversions that Javascript will do for me:

  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>Javascript True / False Testing</title>
  • </head>
  • <body>
  •  
  • <script type="text/javascript">
  •  
  • // Short hand for writing to document.
  • function O( strValue ){
  • document.write(
  • "<p>" + strValue + "</p>"
  • );
  • }
  •  
  • // Short hand for testing boolean.
  • function B( objAny ){
  • // Test argument for true / false,
  • if (objAny){
  • return( "TRUE" );
  • } else {
  • return( "FALSE" );
  • }
  • }
  •  
  • // Test true value.
  • O( "true: " + B( true ) );
  • O( "false: " + B( false ) );
  • O( "null: " + B( null )) ;
  • O( "Zero: " + B( 0 ) );
  • O( "Positive Num: " + B( 1 ) );
  • O( "Negative Num: " + B( -1 ) );
  • O( "String Length: " + B( ("test").length ) );
  • O( "Zero String Length: " + B( ("").length ) );
  • O( "Array Length: " + B( ([1]).length ) );
  • O( "Zero Array Length: " + B( ([]).length ) );
  • O( "Object: " + B( {a:1} ) );
  • O( "Array: " + B( [] ) );
  • O( "Zero AND true: " + B( 0 && true ) );
  • O( "Zero AND One: " + B( 0 && 1 ) );
  • O( "1 AND -1: " + B( 1 && -1 ) );
  •  
  • </script>
  •  
  • </body>
  • </html>

Running the above code, we get the following output:

true: TRUE

false: FALSE

null: FALSE

Zero: FALSE

Positive Num: TRUE

Negative Num: TRUE

String Length: TRUE

Zero String Length: FALSE

Array Length: TRUE

Zero Array Length: FALSE

Object: TRUE

Array: TRUE

Zero AND true: FALSE

Zero AND One: FALSE

1 AND -1: TRUE

I think the biggest confidence builder here is that fact that the number zero is considered false and that any NON-zero number (positive or negative) is considered true. This will make my code much more readable (to me). Sweet! That's what happens when you go ahead and test stuff - you get rid of the mystery.

Tweet This Titillating read by @BenNadel - Javascript's Implicit Boolean Conversions Thanks my man — you rock the party that rocks the body!


Reader Comments

Save even more chars:
Empty string ("") is also false.
Btw, you may use "double negation" instead of "if" statement to convert any value to boolean:

var bool = !!someVar;

So
!!0 == false;
!!1 == true;
!!"ABC" == true;
!!"" == false;

Valery

Reply to this Comment

Empty string is false. Very interesting. I am not sure exactly how I feel about that, but lo and behold, I just tested it and you are dead on the money. I like it, thanks for the hot tip.

Reply to this Comment

I would certainly still use if(strValue.length > 0) over if(strValue) simply because I believe it makes the code more self-documenting. Not everyone knows that an empty string evaluates to false. Any developer (hopefully) can look at if(strValue.length > 0) and tell that you're checking for the string containing one or more characters.

Another thing to consider, is this a "documented" feature of javascript (or ECMAScript)? If so, could it change in future versions? It's pretty much a given that if(strValue.length > 0) will always work.

Writing the tightest code using the fewest characters isn't always the best coding practice. Coding in a manner that makes it easier for other developers to maintain is sometimes higher priority.

Just my 2 cents worth. :)

-----
Lee

Reply to this Comment

@Lee,

I agree with you that using the explicit length makes for more readable code in a lot of cases. However, I'd say that I would also have a comment nearby that explains the intent of the conditional statement. I'm super vigilant about commenting my code so if anyone is confused by the markup, they can probably see what is happening by the comments.

Once this becomes a learned feature of the language, I think people will enjoy using it.

Reply to this Comment

This is very clearly spelled out in the ECMAScript spec (section 9.2): http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf

It's not as clear in the JScript spec, but this appears to be normalizing: http://msdn.microsoft.com/en-us/library/skaay966.aspx

Notice that the spec is much more comprehensive than your tests -- you didn't think of trying empty string (as Lee pointed out) and NaN, for example.

@Lee:
Also notice they agree perfectly -- ditto for the MDC. The way the internet works, there's thousands if not millions of scripts on the Web that would break if this were to change, so rest assured, even if future versions of ECMAScript were penned by idiots and broke backwards compatibility for implicit boolean conversion, no web browser would actually be foolish enough to implement such a change.

I do completely agree that <code>if(str.length > 0)</code> is more clear than <code>if(str)</code>. The real use of implicit boolean conversion is when the choice is between (and this is real code that I just used less than ten minutes ago):

<pre>
if(funcval === undefined || funcval === "")
{
inputbox.appendChild(document.createTextNode(randfunc());
}
else
{
inputbox.appendChild(document.createTextNode(funcval);
}
</pre>

and

<pre>
inputbox.appendChild(document.createTextNode(funcval || randfunc()));
</pre>

There, the enhanced readibility of explicitness is completely swamped by the decreased readibility of inelegance.

Reply to this Comment

@Han
I fully agree with using the || (or ?? in C#) null coalesce operator and I do use it frequently. That makes me wonder why I would prefer if(stringVar.length > 0) over if(stringVar), yet I would prefer alert(stringVar || "Empty!") over the alternative if/else.

I suppose it comes down to the null coalesce operator making the code so much cleaner and precise that it I feel it makes it more self-documenting, but it still requires the future coder looking at the code to know about the null coalesce operator. Maybe that's it, I feel a coder is likely (or at least should) know about the languages operators, but might not know details about how data is implicitly cast.

<shrug> Or maybe it's just that I'm too ADHD and OCD all at the same time. LOL! :)

Reply to this Comment

@Han, @Lee,

At the end of the day, I think it comes down to what you are used to. Before you understand the implicit boolean conversion, it can be confusing. But, once you do understand it, I find that it makes things much easier to understand.

Of course, couldn't the same thing be said about any aspect of the language?

In fact, I'd say that I miss this kind of stuff (especially empty string boolean conversion) in other languages. But again, to each his own.

Reply to this Comment

Interestingly if you do:

true == 2 (or any number besides 0) --> FALSE
true == 1 --> TRUE

also even more interesting:

true == "1" --> TRUE
true == "2" (or any other string besides "1") --> FALSE

if anyone would care to explain this feel free to do so...

Reply to this Comment

@Victor,

Hmmm, interesting. I can't explain the difference there in behavior. Typically, when dealing with truthy / falsey values, I don't explicitly compare them to a boolean - I simply use them AS Booleans. But, this does seem odd.

I can tell you that this works:

  • if (true && 1 && 2 && "1" && "2"){
  • console.log( "it's all true" );
  • }

So, they do all evaluate to "true"; but, apparently they can't always be directly compared to True ... not sure why.

Reply to this Comment

That was just an example I ran into when looking into an application. Personally I would have evaluated it as a bool rather than using comparison.

But nevertheless it's weird, I know that non-empty strings should always be true. Which you've shown above.

Must be an inconsistency of js...

Reply to this Comment

@Victor, @Han,

Thanks for the link - that makes sense then if that's what Javascript is doing for lose comparisons.

Reply to this Comment

Another one that surprised me today:

Try this in a JS console:

"true" == true

( outputs false !! )

if( "true" ) { return "1"; } else { return "2"; }

(outputs "1")

if( "true" == true ) { return "1"; } else { return "2"; }

(outputs "2")

I thought i understood javascript's boolean values but this on still eludes me.

Reply to this Comment

@Iulian:
Your 2nd test ('true'?1:2) throws the true because it is just not false. You could write everything in the string (eg 'yourteststring'?1:2 or even 'false'?1:2). Every string that is not empty is not false. It is evaluated like this 'something'.length?1:2 so with this you can perfectly test if a string variable is undefined or null or just empty what makes it very useful for different things.

Reply to this Comment

@Chris:

Thanks for your answer. I understand how string is "not false" in js, but the weird thing is that you would expect something that is "not false" to be "true" :)

Also this is a bit surprising:

"true" == true => false
"true" == false => false

Reply to this Comment

You are right I think not false is true - since boolean logic means !false => true ;)

As I wrote before a boolean evaluation of a string is different to the evaluation of a boolean. You cannot really compare a different datatype to a boolean (except of 0,1,'0','1') like you can compare a string to a number (eg '2'==2). It is irrelevant that the string you compare to a boolean looks like a boolean.
If you really have to compare 'true' with true there is a quite simple workaround via
JSON.parse('true')==true (for all browsers supporting the JSON object)
or
'true'==true.toString() (for all browsers).
Again 'true' is not a boolean and just because its boolean evaluation returns true it is still not a boolean true. ;)

Hope that helped :)

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.