Falsy, truthy & nullish

Falsy & truthy

Falsy and truthy values are values that are coerced into false and true respectively, when encountered in a boolean context.

The falsy values are:

All other values are truthy! This means that any non-empty string always coerces into true in a boolean context. Thus in JavaScript also "0" coerces into true!

Typical boolean contexts are logical operations and conditions in conditional statements:


console.log( 1 || 0 ); // logs: 1 // Because 1 coerces into true (short-circuiting).
console.log( 'John' && 'Jane' ); // logs: "Jane" // Because "John" coerces into true (short-circuiting).

let condition = 1;
if (condition) { console.log("This gets returned.") } // condition was coerced into true

condition = "Hello";
if (condition) { console.log("This gets returned.") } // condition was coerced into true

condition = '';
if (condition) { console.log("This gets NOT returned.") } // condition was coerced into false

condition = null;
if (!condition) { console.log("This gets returned.") } // condition was coerced into false, but 'not false' is true.	

In other contexts than a boolean context, for instance in a numerical context, values coerce in a different way, as we have seen in the previous chapter. In a numerical context some truthy values are coerced into NaN (console.log("foo" * 2); // logs: NaN) and falsy value NaN is not coerced into 0, but falsy value false is.

Comparison operations do act within a boolean context (they return a boolean) but the comparison is based on a numerical evaluation as we have seen in the previous chapter.

Nullish

So, statement if(someVar) skips execution for any falsy value of someVar. If you want to check for specific falsy (or truthy) values, you can use the strict equality operators.


let someVar = null;	
if (someVar) { console.log("This does NOT get returned."); } // null is falsy, thus the condition is evaluated as false.
if (someVar !== false) { console.log("This DOES get returned."); } // null and false are of different data types. Condition is true.

The non-strict equality comparison operators should be avoided (see previous chapter), except maybe in those situations where you want to check if something is (n)either undefined (n)or null, that is, to check whether something is nullish or not. Value null is only mutually equivalent with undefined (and vice versa) in a non-strict equality check. We have seen this being used before in the equivalent short-circuit function for the nullish coalescing operator ??.


if( foo == null ) { // Only executed if foo is either null or undefined }
if( foo != null ) { // Only executed if foo neither null nor undefined }

// or:

if( foo == undefined ) { // Only executed if foo is either null or undefined }
if( foo != undefined ) { // Only executed if foo neither null nor undefined }

In a previous chapter, we explained the difference between null and undefined. The next example uses the non-strict equality comparison operator with null and undefined.


let myName

function greetingIfDefined(name) {
	// if (name != null) { console.log("Hello "+name+", how ya doin'?"); } // or:
	if (name != undefined) { console.log("Hello "+name+", how ya doin'?"); }
	else { console.log("No greetings for you, you're "+name+"."); }
}

greetingIfDefined(myName); // logs: "No greetings for you, you're undefined."
myName = null;
greetingIfDefined(myName); // logs: "No greetings for you, you're null."
// Anything else than 'null' or 'undefined' is NOT mutually equivalent in a non-strict equality check; condition is true:
greetingIfDefined(false); // logs: "Hello false, how ya doin'?"
greetingIfDefined(0); // logs: "Hello 0, how ya doin'?"
greetingIfDefined(NaN); // logs: "Hello NaN, how ya doin'?"
greetingIfDefined(""); // logs: "Hello , how ya doin'?"
greetingIfDefined("guys"); // logs: "Hello guys, how ya doin'?"
greetingIfDefined(-Math.PI); // logs: "Hello -3.141592653589793, how ya doin'?"

Of course we can also use two strict equality operators and connect them by a logical AND. This involves a little more code, but may make the programmer's intention clearer and the code more comprehensible.


function greetingIfDefined(name) {
	if (name !== null && name !== undefined) { console.log("Hello "+name+", how ya doin'?"); }
	else { console.log("No greetings for you, you're a "+name+"."); }
}

You may be inclined considering the nullish coalescing operator as an option to perform this "nullish check", but this would make things only unnecessary cumbersome.


function greetingIfNotNullish(name) {
	let defined = true;
	name ?? (defined = false);
	if (defined) { console.log("Hello "+name+", how ya doin'?"); }
	else { console.log("No greetings for you, you're a "+name+"."); }
}