When working with JavaScript, there are two important values you will inevitably encounter and will come across in almost every JavaScript project: null
and undefined
. At first glance, both may seem quite straightforward and similar, but each has its own unique characteristics and pitfalls. In this article, we will explore the similarities and differences between these two values, their importance in the JavaScript language, and key aspects worth mentioning.
What is null
?
null
is a primitive value in JavaScript that represents the intentional absence of any object value. It's often used to indicate that a variable or property should hold no value. Similar to how NaN
is a number but represents an invalid number, null
is an object but represents the absence of an object. null
is typically used to explicitly set a variable or property to "no value", with the intention of updating it later.
let user = null;
console.log(user); // null
console.log(typeof user); // "object"
Assume you are accepting input from a user and need to create a user object if the given input is valid. In that case, you would want to perform some checks and create the actual user object (perhaps with the intention of saving to the database) based on the results of these validations.
function addUser(email, password) {
let user = null;
if (validateEmail(email) && validatePassword(password)) {
user = createUserObject(email, password);
} else {
return null;
}
saveToDB(user);
}
The above is one of the most common scenarios where you might need to use null
value. We explicitly indicate that user
variable is meant to hold an object but currently has no value before actually performing the check.
What is undefined
?
undefined
is similar to null
in representing the absence of a valid value. However, the key difference is that it refers to a variable that has been declared but not yet assigned a value. It is the default state for uninitialized variables.
undefined
has its own type: undefined
.
console.log(typeof undefined) // undefined
Because undefined
is default state for all undeclared variables, a variable automatically gets the value undefined
if it's declared but not initialized.
let data;
console.log(data); // undefined
console.log(typeof data); // undefined
If you try to access the return value of a function without a return
statement, you will receive undefined
:
function foo() {}
console.log(foo()) // undefined
Accessing a non-existent object property will also result in undefined
:
const obj = {}
console.log(obj.missingProp) // undefined
The difference betwen null
and undefined
Both null
and undefined
signify an absence of value but their meanings and uses are different. While undefined
represents the absence of a value in a variable that has been declared but not assigned, null
represents an explicitly set and intentional absence of any object value.
null |
undefined |
|
---|---|---|
Type | object |
undefined |
Default value? | No | Yes, for uninitialized variables |
Usage | Intentionally represents absence of value | Implicitly uninitialized |
How to check for null
and undefined
?
Checking for null
The strict equally operator is used to check if a value is null
.
let value = null;
if (value === null) {
console.log("The value is null");
}
Please note that strict equally operator is always a better choice than the loose equality (==
) operator since the latter considers both null
and undefined
as equal, which can lead to unintended results.
let value;
if (value == null) {
console.log('value is null');
}
console.log(value); // undefined
When you run the code block above, the output will be as follows::
value is null
undefined
Even though the value of our variable is undefined
, the loose equality operator considers null
equal to undefined
. Therefore, the strict equality operator (===
) is always a better choice for null
checks.
let value;
if (value === null) {
console.log('value is null'); // this line won't be executed
}
console.log(value); // undefined
You can see how the loose equality operator (==
) behaves with null
and undefined
values:
console.log(null == undefined); // true
console.log(null === undefined); // false
Checking whether a value is falsy is also not ideal, as null
is not the only falsy value in JavaScript.
let value = '';
if (!value) {
console.log('value is null');
}
console.log(typeof value); // string
When you run the code above, the output will be:
value is null
string
if
condition above can be true
for any falsy value.
Checking for undefined
The strict equality operator is also used to check if a value is undefined
:
let value;
if (value === undefined) {
console.log("The value is undefined");
}
You can also use the typeof
operator:
let value;
if (typeof value === 'undefined') {
console.log("The value is undefined");
}
You can use the in
operator to check if a property exists in an object.
const obj = {};
if (!("prop" in obj)) {
console.log("Property does not exist");
}
Best practices for handling null
and undefined
JavaScript provides convenient features to handle null
and undefined
values with ease. As you spend more time writing JavaScript, you will find yourself using these features more frequently.
Optional chaining operator (?.
)
The Optional Chaining operator allows you to safely access deeply nested properties without worrying about undefined
or null
values causing an error. It was introduced in ES2020 and has quickly become one of the most used features of the language because it simplifies checking for nested values.
const person = {
name: 'John',
cat: {
name: 'Misty',
},
};
console.log(person.cat?.name); // Misty
console.log(person.dog?.name); // undefined
Even though the dog
attribute does not exist, we get an undefined
value instead of a runtime error because the optional chaining operator checks for null
and undefined
before attempting to access the property.
We can also use it when calling methods.
const person = {
name: 'John',
cat: {
name: 'Misty',
},
};
person.cat.greet = function() {
return `Hello, my name is ${this.name}`;
};
console.log(person.cat?.greet()); // Hello, my name is Misty
console.log(person.dog?.greet()); // undefined
It is possible to use this operator before function parentheses in case the method itself is either null
or undefined
const person = {
name: 'John',
cat: {
name: 'Misty',
},
};
person.greet = function() {
return `Hello, my name is ${this.name}`;
};
console.log(person.greet()); // Hello, my name is John
console.log(person.foo?.()); // undefined
Nullish coalescing operator (??
)
The Nullish Coalescing operator (??
) is used to provide a default value when a variable is either null
or undefined
. It was introduced in ES2020 and works as a more predictable alternative to the logical OR (||
) operator when dealing specifically with null
and undefined
.
let person = null;
let personName = person?.name ?? 'Anonymous';
console.log(personName); // Anonymous
Before the ??
operator, the logical OR (||
) operator was commonly used for fallback values. However, the logical OR operator has a broader scope as it treats all falsy values as triggers for the fallback.
const value = 0 || 100;
console.log(value); // 100 (unexpected, as 0 is falsy)
const value2 = 0 ?? 100;
console.log(value2); // 0 (expected behavior, as 0 is a valid value)
Nullish coalescing assignment (??=
) operator
The Nullish Coalescing Assignment (??=
) operator is a shorthand introduced in ES2021 that allows you to assign a value to a variable only if it is currently null
or undefined
.
myvar ??= myval
If myvar
is null
or undefined
, it assigns the value on the right. If it already holds a value (including 0
, false
, ""
), it does nothing.
let username;
username ??= "Guest";
console.log(username); // "Guest"
let age = 0;
age ??= 18;
console.log(age); // 0 (since 0 is a valid value)
Conclusion
null
and undefined
are important concepts in JavaScript, and understanding the difference between them is crucial for writing clean and robust code. Although there are some tricky parts and pitfalls, the difference is quite straightforward: you should expect undefined
when variables or properties are uninitialized, while null
represents the intentional absence of a value. Modern operators, such as the optional chaining operator, help you handle null
and undefined
values more efficiently by reducing the need for multiple conditions. As you spend more time working on JavaScript projects, you will use these values and operators more frequently and gain a better understanding of how they are powerful tools for writing robust and predictable JavaScript code.