Let's dive into the intriguing world of truthy and falsy values in JavaScript. We'll explore their fundamental concepts and dissect their impact on logical operations within the JavaScript language.
It's important to note that not all values inherently possess a Boolean nature. So, you might be wondering: How can a value that isn't inherently boolean be transformed into one? The exclusive method for non-boolean values to take on a Boolean identity is through "truthy" or "falsy" coercion.
Understanding these concepts can pave the way for more succinct and expressive code. But before we dive into practical code examples, let's first acquaint ourselves with the roster of truthy and falsy values.
In JavaScript, type coercion is used to implicitly convert values from one data type to another within Boolean contexts, such as conditionals. This means that values are categorized as truthy when they evaluate to true or falsy when they evaluate to false, depending on how they are assessed in a Boolean context.
Now, let's explore some engaging examples to solidify our understanding and leverage these concepts for more powerful JavaScript code.
What are truthy and falsy values?
Lists of Falsy values
false
0
-0
0n
'', "", ``
null
undefined
NaN
I begin with falsy values because any value that isn't falsy is considered truthy even ones that might seem falsy, such as empty arrays ([]), string containing a single ‘0’ or ‘false’ or empty objects ({}).
Lists of Truthy Values
'0' (String containing a single zero)
'false' (String containing the text “false”)
[] (an empty array)
{} (an empty object)
function(){} (empty function)
Now we know what are the truthy and falsy values. Let's write a function to determine whether a given value is considered "truthy" or "falsy" based on JavaScript's type coercion rules.
function truthyOrFalsy(value){
if(value !== false && value !== 0 && value !== '' && value !== null && value !== undefined && value !== 0n && !Number.isNaN(value)){
console.log("I'm Truthy");
} else {
console.log("I'm Falsy");
}
}
truthyOrFalsy(-0) // I'm Falsy
truthyOrFalsy(0) // I'm Falsy
truthyOrFalsy('') // I'm Falsy
truthyOrFalsy(false) // I'm Falsy
truthyOrFalsy(null) // I'm Falsy
truthyOrFalsy(undefined) // I'm Falsy
truthyOrFalsy(0n) // I'm Falsy
truthyOrFalsy(true) // I'm Truthy
truthyOrFalsy(1) // I'm Truthy
truthyOrFalsy([]) // I'm Truthy
truthyOrFalsy({}) // I'm Truthy
truthyOrFalsy('Hello World') //I'm Truthy
The function takes one argument, value, which represents the value being evaluated. Inside the function, there is an extensive conditional statement that checks various conditions to classify the input value. Each condition checks whether the value is not equal to a specific falsy value or is not of a specific type, ensuring that the value passes a set of checks to be classified as "truthy." However, there is a problem with this extensive conditional statement in the function that makes the code hard to read, prone to errors, and challenging to maintain due to its repeated comparisons and complexity.
For this reason, let's consider a better way to simplify the conditional statement to enhance code readability and conciseness, leading to more efficient and maintainable code.
When to implicitly check the values.
Concise Conditional Statements:
Write shorter, more readable code by leveraging truth and falsy values in conditional statements.
function truthyOrFalsy(value){
if(value){
console.log("I'm Truthy");
} else {
console.log("I'm Falsy");
}
}
truthyOrFalsy(-0) // I'm Falsy
truthyOrFalsy(0) // I'm Falsy
truthyOrFalsy('') // I'm Falsy
truthyOrFalsy(false) // I'm Falsy
truthyOrFalsy(null) // I'm Falsy
truthyOrFalsy(undefined) // I'm Falsy
truthyOrFalsy(0n) // I'm Falsy
truthyOrFalsy(true) // I'm Truthy
truthyOrFalsy(1) // I'm Truthy
truthyOrFalsy([]) // I'm Truthy
truthyOrFalsy({}) // I'm Truthy
truthyOrFalsy('Hello World') //I'm Truthy
Default Values:
You can easily set default values for variables using the || (logical OR) operator. This is particularly useful when a variable might be falsy, and you want to provide a default value in that case.
function greet(name) {
name = name || "Guest"; // Set "Guest" as default if name is falsy
console.log("Hello, " + name);
}
greet(); // Output: Hello, Guest
greet("Alice"); // Output: Hello, Alice
Cleaner Type Conversion:
When performing type conversion, truthy and falsy values are useful. For example, converting a value to a boolean using the Boolean() constructor function.
console.log(Boolean(0)); // Output: false
console.log(Boolean("Hello")); // Output: true
console.log(Boolean(null)); // Output: false
Short-Circuiting:
Logical operators (&& and ||) take advantage of truthy and falsy values to perform short-circuit evaluation. This means that the second operand of a logical expression might not be evaluated if the first operand determines the overall truthiness or falsiness of the expression.
let result = true || someFunction(); // someFunction() won't be called because true || anything is always true
Implicit Type Coercion:
JavaScript uses truthy and falsy values in type coercion, which can be advantageous when performing comparisons or calculations.
console.log(1 + true); // Output: 2 (true is implicitly coerced to 1)
console.log("hello" || "world"); // Output: "hello" (truthy value is returned)
However, while truthy and falsy values can simplify code in many cases, they can also lead to unexpected behavior or bugs if not used carefully.
It's important to be aware of how these values are used and how they might affect your code's logic. Knowing when to use truthy and falsy values will make you a better Javascript developer. Have no worries I will show you the weird part or problem of truthy and falsy values so you can be the captain of your code ship 😉 .
When to explicitly check the values.
To clearly understand when to explicitly check a value, let's consider a scenario where an e-commerce app has a friends_Referred feature and there are two types of accounts: Business account and consumer account but the only account with the friends_Referred feature is the consumer account indicated in the accounts object code provided below.
const accounts = [
{
full_name: "Grace Adams",
mail_address: "grace.adams@example.com",
account_type: "business"
},
{
full_name: "Robert Johnson",
email_address: "robert.johnson@example.com",
account_type: "consumer",
friends_referred: 0
}
]
for (const account of accounts) {
console.log(`${account.full_name}'s Information:`);
if (account.friends_referred) {
console.log(`Friends Referred: ${account.friends_referred}`);
} else {
console.log("Friends Referred: Not Available");
}
console.log("---------------");
}
// Output
Grace Adams's Information:
Friends Referred: Not Available
---------------
Robert Johnson's Information:
Friends Referred: Not Available
---------------
The result of the code output is the else path for both accounts even though friends_Referred is defined for the Robert Johnson account. I believe you may ask why this happened and how can we fix our code? Good question, the answer is the if condition evaluates to false for both accounts because the first account doesn’t have the refer-a-friend which evaluates to Undefined, and the second account evaluates to false. As Undefined and 0 are both falsy values.
const accounts = [
{
full_name: "Grace Adams",
mail_address: "grace.adams@example.com",
account_type: "business"
},
{
full_name: "Robert Johnson",
email_address: "robert.johnson@example.com",
account_type: "consumer",
friends_referred: 0
}
]
for (const account of accounts) {
console.log(`${account.full_name}'s Information:`);
if (account. friends_referred !== undefined) {
console.log(`Friends Referred: ${account. friends_referred }`);
} else {
console.log("Friends Referred: Not Available");
}
console.log("---------------");
}
// Output
Grace Adams's Information:
Friends Referred: Not Available
---------------
Robert Johnson's Information:
Friends Referred: 0
---------------
In the provided code, explicit checks are used to ensure that the property friends_referred exists in the accounts objects before attempting to access its value. This approach is used to prevent potential errors or unexpected behavior when handling different types of accounts within the loop.
Here's why explicit checks are used in this context:
Handling Undefined Property:
The code needs to handle situations where the friends_referred property may or may not be present in the accounts objects. If the property is missing, trying to access its value directly would result in an undefined value. To avoid this, an explicit check is used to verify the existence of the property before accessing it.
Different Account Types:
The accounts array includes both "business" and "consumer" accounts. While the "consumer" accounts have the friends_referred property, the "business" accounts do not. By explicitly checking for the existence of the property, the code accommodates both types of accounts without causing errors or confusion.
Clarity and Readability:
The explicit check enhances the code's readability and clarifies the developer's intention. When someone reads the code, it's immediately clear that the code is handling scenarios where the friends_referred property might not be available for all accounts.
Preventing Unexpected Behavior:
Relying solely on truthy/falsy evaluations might lead to incorrect assumptions, especially when dealing with different account types. Using explicit checks guarantees that the code behaves as intended regardless of the specific values of the property.
Overall, explicit checks are used in this code to create a more robust and reliable loop that handles potential variations in the structure of the accounts objects. By confirming the presence of the friends_referred property, the code avoids potential errors and provides accurate information when displaying the number of friends referred for each account.
Conclusion
In JavaScript programming, both implicit and explicit value checking offer distinct advantages for handling conditions and ensuring reliable code behavior. Implicit value checking leverages JavaScript's built-in truthy/falsy evaluation, promoting concise code and simplifying conditional statements. On the other hand, explicit value checking provides greater control and accuracy by directly verifying specific conditions or properties. While implicit checking enhances readability, explicit checking offers better handling of edge cases, input validation, and unexpected behavior prevention. A skilled JavaScript programmer utilizes both approaches strategically, depending on the context, to create robust and well-maintained code.