Undefined vs. Null
In the years that I've spent reading about and writing in JavaScript I've come across a lot of confusion around undefined
and null
. On the surface, they might seem interchangeable. In fact, undefined
and null
share a number of similarities:
- Both are Primitives in JavaScript
- Both represent a lack of value
- Both are Falsy Values
- Because of this, when we do a loose-equals comparison of
undefined == null
, the language returnstrue
- Because of this, when we do a loose-equals comparison of
If they loosely evaluate to be the same thing, it's not a major stretch to think that they are completely interchangeable. That's not the case though.
The key practical difference is that undefined
is most commonly seen as the value that the JavaScript compiler assigns to a variable when a variable is declared, but not given a value. null
on the other hand must be deliberately assigned as the value of a variable by the developer. The language and the compiler will never assign anything the value of null
.
So that's the short explanation, but I'm not content to stop there. Let's once again dig deep into the language and its fundamentals to really understand what undefined
and null
really are, how they behave, what sets them apart from one another, and when you might encounter or use them.
Primitive Types in JavaScript
In JavaScript, there are nine data and structure types. These can be further broken down into the following categories:
Six Primitive Data Types:
undefined
- Boolean
- Number
- String
- BigInt
- Symbol
Two Structural Types:
- Object
- Function
One Structural Root Primitive:
null
The focus of this blog post isn't on each of these data types, but instead on undefined
and null
, which at an initial glance are very similar.
From the list above, undefined
and null
stand out as values that both denote a lack of value. With a Number, you can imagine values such as 1
or 100
or 1000
. With a String you might imagine something like "Joey drove his car"
or "Slightly Overcast"
or "Red"
. With an Array you might imagine a list like ["eggs", "bacon", "butter", "milk"]
, and so on for the other Primitives. With undefined
and null
, conceptually they seem to represent non-value, some kind of void.
Going further, in his book You Don't Know JS: Types & Grammar, Kyle Simpson points out something interesting about these two Primitives:
For the
undefined
type, there is one and only one value:undefined
. For thenull
type, there is one and only one value:null
. So for both of them, the label is both its type and its value.
The lack of value also feels related to another concept in JavaScript, the concept of Falsy Values.
Falsy Values
A Falsy Value is a value that evaluates to false
when used in a Boolean context. What does this mean? Well let's take a look at the following:
const daylightSavingsTime = false;
if (daylightSavingsTime) { console.log("We are one hour back"); // This doesn't run}
The code inside of the if
block does not run because daylightSavingsTime
is false
. We are using a plain Boolean value here, but we can do similar work with non-Boolean values that evaluate to false
. Here's an example:
const string = ""; // Empty string
if (string) { console.log(string); // This doesn't run}
Again, the block within the if
statement only runs if the condition that has been passed evaluates to true
. We passed in an empty string, which evaluates to false
, and the code in the block does not run. The empty string evaluates to false
because an empty string is a Falsy Value.
There are six Falsy Values in JavaScript:
false
(Boolean)- 0 (the Number 0)
- "" (an empty String)
null
undefined
NaN
(Not a Number)
Again, this blog post is not focusing on Falsy Values, but instead I wanted to highlight the topics of null
and undefined
and the fact that they are both Primitive Types and Falsy Values in JavaScript.
What is undefined
?
undefined
is a type that occurs when a variable is declared but not assigned a value. Consider the following code:
let ingredients = ["bacon", "eggs", "butter"];console.log(ingredients); // ["bacon", "eggs", "butter"]
let recipe;console.log(recipe); // undefined
First we create an ingredients
variable by declaring it. Then, using the =
equals sign, assign it the value of an array containing a few strings.
When we console.log
ingredients
, the console prints out the array and its contents. Pretty simple.
Below that we create a recipe
variable, but do not assign any value to it. recipe
exists in name space, but it contains no data. Because of this, when we console.log
recipe
, the console returns undefined
.
This code demonstrates the most common way that an undefined
value or type will be encountered, which is when a variable has not been assigned a value.
Per MDN:
A variable that has not been assigned a value is of type
undefined
. A method or statement also returnsundefined
if the variable that is being evaluated does not have an assigned value. A function returnsundefined
if a value was not returned.
So the prevailing pattern is that undefined
is something the language compiler assigns to values that are declared, but not given any other value. That's true, but it should also be pointed out that you can deliberately set a variable to equal undefined
:
let recipe = undefined;console.log(recipe); // returns undefined
However this practice seems to be something of an anti-pattern and I would advise against it. More on this later, but if you feel drawn to deliberately assign a lack of value to a variable, I think it is best to use null
.
You may also encounter undefined
if you are trying to access non-existent properties on an object:
const person = { name: "Joey", sayHi: function () { console.log(`Hi ${this.name}`); },};
console.log(person.name); // "Joey"console.log(person.age); // undefined - no 'age' property
typeof
and undefined
I would like to take a moment to note the behavior of the typeof
operator with an undefined
variable.
let recipe;console.log(typeof recipe); // returns undefined
As you'll see in this example, typeof
, when used with an undefined
value, returns undefined
. This may seem like a tautology, but I want to highlight the way that typeof
can cause some confusion.
There's an important distinction to be drawn between an "undefined" variable and an "undeclared" variable, since these two terms sometimes get used interchangeably. As I've said before, "undefined" refers to a variable within the accessible scope that has not been assigned a variable. However, an "undeclared" variable is one that has not been declared or created within scope. Consider this example:
var name;name; // undefinedage; // ReferenceError: age is not defined
When calling a variable that has been declared but not assigned a value, undefined
is returned. However, when calling a variable that has been neither declared nor assigned a value, a ReferenceError
is thrown, stating that the variable is "not defined". This wording is unfortunate, since linguistically "undefined" and "not defined" mean the same thing in English.
Furthering the confusion is how typeof
works with the same two variables:
var name;console.log(typeof name); // undefinedconsole.log(typeof age); // undefined
Huh. So typeof
will return undefined
for both undefined and undeclared variables. Again I'm simply writing all of this to illustrate how there could be confusion surrounding "undefined" variables and "undeclared" variables.
undefined
as an Identifier
Let's go even further into the weeds! undefined
is technically an identifier (whereas null
is a keyword). This means that in non-strict
mode, it's possible to assign a value to the global undefined
identifier.
function badIdeaNeverDoThis() { undefined = 100; // I can't tell you how bad of an idea this is}
badIdeaNeverDoThis(); // global undefined has been reassigned
strict
mode does not allow this global identifier to be reassigned.
function badIdeaNeverDoThis() { "use strict"; undefined = 100; // TypeError}
badIdeaNeverDoThis();
However in both non-strict
mode and strict
mode you can create a local variable named undefined
. This is also a really bad idea, don't do this.
function badIdeaNeverDoThis() { "use strict"; var undefined = 100; console.log(undefined); // 100}
badIdeaNeverDoThis();
Void
Another way to get undefined
is through the void
operator. This operator always returns undefined
without modifying the existing value.
var age = 33;console.log(age); // 33console.log(void age); // undefined
This is a bit of a niche language feature, but I imagine it could have interesting uses when working with certain templating languages. Handlebars comes to mind.
What is null
?
null
is an assignment value that can be assigned to a variable to represent that that variable holds no value.
let empty = null;console.log(empty); // returns null
So null
as a value represents something that is empty or non-existent, and null
must be deliberately assigned within the code. The compiler will not automatically set something to null
.
Per MDN:
The value
null
is written with a literal:null
.null
is not an identifier for a property of the global object, likeundefined
can be. Instead,null
expresses a lack of identification, indicating that a variable points to no object. In APIs,null
is often retrieved in a place where an object can be expected but no object is relevant.
typeof
and null
I also want to draw attention here to how the typeof
operator works with a null
value:
let empty = null;console.log(typeof empty); // returns object
Where typeof undefined
returns undefined
, typeof null
returns object
. This is widely regarded as a bug in the language that has existed for a very, very long time. It's been a bug for so long that a lot of code out on the web relies on typeof null
to return object
, and fixing the bug would create even more bugs and break all kinds of currently running applications.
Comparing null
and undefined
So what happens if we start comparing these two types directly?
What do we get if we compare using loose-equals comparison?
null == undefined; // trueundefined == null; // true
A loose-equals comparison, which allows for type-coercion, yields true
, since these are both Falsy Values.
What happens if we do a strict-equals comparison, which doesn't allow for type-coercion?
null === undefined; // falseundefined === null; // false
Unsurprisingly, when type coercion isn't allowed, the two values are deemed to not be strictly equal to one another, since they are of different types.
Default Parameters
Another interesting (and more practical) comparison comes by way of Tim Branyen, though I found it in Brandon Morelli's JavaScript — Null vs. Undefined article. It comes into play when using default parameters in a function call.
Let's take a look at the following function, which will greet you by name.
function sayMyName(name = "Joey") { console.log(`Howdy ${name}`);}
If we call the function as it is, it will use the string "Joey" as the default value for the name
parameter.
sayMyName(); // "Howdy Joey"
We can also pass in a new name as an argument, overriding the default, like so:
sayMyName("Bart"); // "Howdy Bart"
So what happens when we pass undefined
or null
as the argument?
sayMyName(undefined); // "Howdy Joey"sayMyName(null); // Howdy null
Passing undefined
will fall back to the default parameter value, where null
will simply use null
.
Nullish Values
If you're still with me and not totally lost yet then I both commend you and invite you to venture even further into the weeds with me. Let's talk about Nullish Values.
Per MDN:
In JavaScript, a nullish value is the value which is either
null
orundefined
. Nullish values are always falsy.
That is the totality of their article on Nullish Values. It seems to be less of a type classification and more a loose specification that something is a non-value that is represented either by undefined
or null
. It seems to mostly come into play with some of JavaScript's less-commonly used features, like Optional Chaining (.?
) and the Null Coalescing Operator (??
).
I'll admit that I have not used either of these features in production, so what I represent here may not be the most complete or experienced picture, but the spirit of this blog is to dive as deep as possible, so let's go.
Optional Chaining (.?
)
Optional Chaining, represented in the language by a period and question mark (.?
), is a way to safely access Nullish Value properties in an object, that is, those that may be undefined
or null
. As async programming has become more popular (think of all of the React applications out there that rely on data fetched from API calls), some common problems have emerged:
- Data may not be available yet. Sometimes your API is slow or a certain async function hasn't resolved just yet
- Data may be so deeply nested within sub-arrays and sub-objects that locating that data can be error-prone
Using default values and default props can help with some of these issues, but with classic JavaScript access methods, one of the issues listed above may just throw an error that crashes your entire application.
For some time developers were using Lodash to simply return undefined
as a safe, catch-all response if these kinds of errors were encountered. Optional Chaining enables this behavior without the need for an external library.
Read more about Optional Chaining in this FreeCodeCamp article.
Null Coalescing Operator (??
)
The Null Coalescing Operator is represented by two question marks (??
), which separates two expressions. If the first, left hand, expression is Nullish (i.e. either undefined
or null
), then the second, right hand, expression gets returned. If the first, left hand, expression is anything other than undefined
or null
, then that is the expression that gets returned.
Here's an example:
const nullThing = null;const falsyThing = "";const string = "Here's a string";
const firstTest = nullThing ?? string;console.log(firstTest); // "Here's a string"
const secondTest = falsyThing ?? string;console.log(secondTest); // ""
In the case of firstTest
, the left hand expression is a null
value, so the right hand expression gets returned.
In the case of secondTest
, the left hand expression, an empty string, is a Falsy Value, but not undefined
or null
, so the Nullish Coalescing Operator returns the empty string.
Contrast this behavior with the better-known Logical Or Operator (||
), which returns the right hand expression if the left hand expression is any Falsy Value:
const nullThing = null;const falsyThing = "";const string = "Here's a string";
const firstTest = nullThing || string;console.log(firstTest); // "Here's a string"
const secondTest = falsyThing || string;console.log(secondTest); // "Here's a string"
Since in both the firstTest
and secondTest
the left hand expression is a Falsy Value, the right hand expression is returned.
Read more about the Nullish Coalescing Operator on MDN.
When to Use undefined
or null
So when should you use undefined
and when should you use null
?
The rule that I try to follow is that I never set anything as undefined
myself. I will often create a variable without assigning it a value, at which point the JavaScript compiler will designate it as undefined
. This is not something I consciously do in my code.
If I need to create a variable and deliberately designate it as not having a value, I will use null
.
Summary
So let's put it all back together.
undefined
and null
share a number of similarities:
undefined
andnull
are both Primitives- They are the only two Primitives where the label is the same as the value
undefined
andnull
are both Falsy Valuesundefined == null
will returntrue
as loose equality allows for type coercion
undefined
andnull
both represent non-Value in an abstract kind of way- Because of this, a special classification called "Nullish Values" encompasses anything that is either
undefined
ornull
. This mostly seems to come into play when using Optional Chaining (.?
) and the Null Coalescing Operator (??
)
- Because of this, a special classification called "Nullish Values" encompasses anything that is either
But that's about where the similarities end. There are differences in applications and uses between undefined
and null
:
undefined
represents the value of a variable that has been declared, but not assigned a value. The JavaScript compiler will designate a variable asundefined
that has not been given a value- There is a difference between an "undefined" variable and an "undeclared" variable, but the
typeof
operator and default language from aReferenceError
message can cause confusion - A programmer may also deliberately set the value of a variable to be
undefined
, but this is considered an anti-pattern
- There is a difference between an "undefined" variable and an "undeclared" variable, but the
null
is an assignment value representing a lack of any other value. A variable must be assigned the value ofnull
by the programmerundefined
is an identifier, meaning that in certain contexts (non-strict
mode and within local scoping),undefined
can be reassigned to another value. This is not a good ideanull
is a keyword and cannot be reassigned- Using the
void
operator will also always return anundefined
value (regardless of, and without modifying, the original value of the data you are "voiding") undefined === null
will returnfalse
as strict equality does not allow for type coercion, andundefined
andnull
are different typestypeof undefined
will returnundefined
, buttypeof null
will returnobject
. This latter detail is a long-standing error within the language- When used in conjunction with default parameters, passing
undefined
as a function's argument will cause the function to fall back to the default parameter. Passingnull
does not
Did I miss anything at all? Do you feel anything could be clarified or corrected in this deep dive? If you think so, please reach out to me by email. I'm always happy to issue a correction or add any information and give credit or attribution. Or just let me know what you like or don't like about this post or any others!
Sources / Further Reading
Here are posts, articles, and documentation that I used in writing this blog post:
- JavaScript — Null vs. Undefined by Brandon Morelli
- What is the difference between null and undefined in JavaScript? Thread on Stack Overflow
- JavaScript Null vs Undefined by Aiman Rahmat
- You Don't Know JS: Types & Grammar by Kyle Simpson
- JavaScript data types and data structures on MDN
- Undefined on MDN
- Null on MDN
- Falsy on MDN
- Falsy Values in JavaScript on FreeCodeCamp
- JavaScript Basics: Truthy and Falsy values in JavaScript by Yogesh Chavan
- JavaScript Optional Chaining
?.
Explained - How it Works and When to Use it by Shruti Kapoor on FreeCodeCamp - Nullish coalescing operator (??) on MDN