Skip to main content
Ben Nadel at Scotch On The Rocks (SOTR) 2011 (Edinburgh) with: James Allen
Ben Nadel at Scotch On The Rocks (SOTR) 2011 (Edinburgh) with: James Allen

Comparing Undefined Values With Optional Chaining In JavaScript

By
Published in Comments (2)

Yesterday, while working on some HTMX experiments, I stumbled upon a feature of JavaScript that I didn't known: the undefined value, when compared to Booleans and numbers, always returns false. I've always thought of undefined as a falsy value (which it is); so, I was very surprising to see that undefined did not soft equal false. But, this turns out to be hugely beneficial when it comes to the optional chaining operator (aka, the safe navigation operation) in JavaScript.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

First, let's just run a test to see how the undefined value behaviors. In the following script, I'm going to evaluate a number of statements in which we compare undefined to various Booleans and numbers:

var comparisons = [
	"undefined == false",
	"undefined == true",
	"undefined == 0",
	"undefined > 0",
	"undefined >= 0",
	"undefined < 0",
	"undefined <= 0",
];

for ( var test of comparisons ) {

	console.group( `Testing: %c${ test }`, "color: red" );
	console.log( `%c${ eval( test ) }`, "background: yellow" );
	console.groupEnd();

}

I'm iterating over the statements and evaluating each one of them using eval(). And, when we run this JavaScript code, we get the following output:

A series of JavaScript comparisons, all resulting in false.

As you can see, each one of these JavaScript comparisons to undefined results in false.

This was the surprising behavior (to me). I had always just assumed that undefined would be soft equal to false (it is to null, by the way). But, the fact that undefined results in a false comparison becomes very helpful in the context of the safe navigation operator.

Consider the following expression:

data.optionalInput.indexOf( "x" ) >= 0

In this case, if optionalInput is undefined, this expression will throw a null reference error (NRE) because .indexOf() is not a valid method on undefined. We can combat this by including the safe navigation operator prior to the method call:

data.optionalInput?.indexOf( "x" ) >= 0

Now, if the optionalInput property is undefined, the expression will short-circuit and evaluate to undefined; which leaves us with this comparison under the hood:

undefined >= 0

Historically, I've always assumed that this would result in true since I always assumed that undefined would match on the = 0 part of the >= 0 comparison. But, as we've demonstrated above, the undefined value always results in false when compared to numbers. Which means this:

undefined >= 0

... results in false!

This JavaScript behavior can simplify our if blocks when it comes to things lie the indexOf() comparison. Consider this workflow:

var inputs = {};

// Note: "value" is an undefined property.
if ( inputs.value?.indexOf( "hello" ) >= 0 ) {

	console.log( "Hello Found!" );

} else {

	console.log( "Hello Not Found" );

}

With my old assumptions about the JavaScript behavior, I would have expected the comparison to result in true since I, again, had historically assumed that the undefined value produced by the safe navigation operator (short-circuiting the left-hand expression) would have matched on 0. But, it doesn't! Which means that when we run the above JavaScript code, we get the following log:

Hello Not Found

This is awesome! It means that I don't have to dance around the possibility of an undefined value in my if conditions. Unless I'm explicitly comparing it to null or undefined, I can safely use undefined values (and more specifically, I can safely use the optional chaining operator) without accidentally entering my "truthy block".

I can't believe I didn't know this about JavaScript! It's going to make a few types of scenarios easier to code.

And, to be clear, my historical assumption isn't that crazy. After all, this comparison:

false >= 0

... does result in true (since false soft equals 0). And, in my mind, false and undefined were roughly equivalent. It was my bad to assume this; but, it's not like I was just making it up out of thin air - it was based on some degree of reasonable logic. My logic just happened to be built on incorrect facts.

Learning for the win!

Want to use code from this post? Check out the license.

Reader Comments

Post A Comment — I'd Love To Hear From You!

Post a Comment

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel