Essential JavaScript: Mastering null vs undefined

Credits: Edited version of

Mastering and in JavaScript is often underrated. Because and get coerced to , developers who are new to JavaScript often getaway by treating both these values as or . But mastering how these two values mean two completely different things helps you write bug-free code instead of relying on guesswork.

(To simplify, we will use the terms and interchangeably.)

A tale of two nothings

Both and are special to represent nothingness. By the end of this article, you will understand what we mean by “nothingness,” and two different types of “nothingness” that and primitive values represent.

Most programming languages use a single value, which is often called to represent that a reference type has no value associated with it. But JavaScript is special! And that is why you are reading this deep-dive on a seemingly simple concept.

Before we get to and , let’s understand what happens when we use a variable that’s never declared.

undeclared: non-existence

On line 4, the variable does not exist. If you run this code in the console, you will see an error like the following:

ReferenceError: universe is not defined

That’s fair given we haven’t declared anywhere. This is what we mean by undeclared variables. JavaScript engine throws a when it’s unable to find an identifier in all of the accessible scopes. There is a nuance here when we try to assign a value to an undeclared variable in .

The following code will create a global variable in .

Let’s safely ignore this nuance in this article and simplify our statement:

When the JavaScript engine is unable to find a variable, it throws a ReferenceError.

Now let’s add one more line(#5) to the above code.

In the above snippet, line 5 never executes. Line 4 throws an error and halts the JavaScript execution right there. This is a subtle but critical detail as you are going to learn in the following sections. It may surprise you to know that in my interviews I often see junior JavaScript engineers answer they will see the alert from line 5. I can always paraphrase their reasoning as “JavaScript is very forgiving!”

uninitialized: existence without a value

Now let’s declare our intention that we will create a sometime in the future.

In this snippet, is declared on line 1, but we haven’t assigned any “explicit” value to it. When we try to access its value on line 2, is printed to the console. That’s not bad given we just declared a variable and never assigned any value to it. We expect that some mystical JavaScript supreme-being will create a universe in the future when it’s time for the big-bang.

If were the word used for , a lot of confusion would have been avoided as you are going to realize in the following sections.

All that we have got now is an intention that we may create a in the future. It holds no value as of now. It’s not even an “explicit” empty value. It’s emptiness beyond emptiness!

represents a lack of an explicitly assigned value in a variable or in other words, a missing value.

Quoting verbatim from the ECMAScript® 2020 Language Specification:

undefined value
primitive value used when a variable has not been assigned a value.

It’s time for that big-bang to happen!

In this snippet, lines 4 to 6 create a new object and assign it to the variable. Now our variable has an object value.

The key takeaway here is that JavaScript assigns the primitive value when a variable doesn’t have an explicitly assigned value.

But what if we do explicitly? Continue reading to find the answer!

null: intentionally empty

is a primitive value to represent an “intentional” absence of any other assigned value.

In this example, we intentionally indicate that the exists, but it is initialized “explicitly” with an represented by . It is a special value to represent it has no value :) That’s an existential paradox in the JavaScript universe!

In the above snippet, line 3 outputs as expected. Lines 6 to10 work like the example we have seen before with the .

Quoting verbatim from the ECMAScript® 2020 Language Specification:

null value
primitive value that represents the intentional absence of any object value.

If you have read the above sentence keenly, you would have noticed that actually represents the intentional absence of an “object value.”

Because JavaScript uses dynamic types, when a variable is declared and is not assigned a value, there is no way to differentiate it between the and the . So as per the specification represents an absence of an object value.

JavaScript never implicitly assigns to anything; programmers have to explicitly assign .

JavaScript vs Java

Empty values are not specific to JavaScript alone. In traditional object-oriented programming languages like Java, represents an uninitialized value for object types. Primitive types like , , etc. have default values that are of primitive type. For example, a variable in Java is initialized with .

JavaScript uses dynamic types, or in other words a variable can hold both primitive types and object type.

In summary, we have learned that the primitive value is used to represent the explicit absence of an object value, while the primitive value is used to represent no assigned value.

null and undefined are falsy values

There is one thing that and share in common: both and are coerced to when encountered in a Boolean context. Both and values are considered as in JavaScript.

In the following code snippet, neither of the evaluates to .

This is why you very often see code like the following:

undefined === null vs undefined == null

null and undefined with function parameters

JavaScript functions love ! They share an immortal bond!

When a function is called with fewer parameters than it formally expects, missing values will automatically become . Let’s see a simple example.

In the above snippet, line 5 works as expected.

But line 6 is more interesting! We call without passing any value for the parameter . Since is a local variable to the function , and there was no value passed to it, the JavaScript engine initializes its value with .

Now let’s see something even more interesting.

In the above snippet, line 5 and line 6 both print . Line 6 explicitly passes . But in the function, there is no way to distinguish between the missing parameter value(line 5) vs. using as the parameter value(line 6).

But on line 6, what is exactly? We will answer this important question soon.

Line 7 calls with to represent an explicit absence of a value. JavaScript doesn’t replace it with because it's an explicit empty value.

default values for function parameters

JavaScript allows default values for function parameters.

In the following snippet, we have modified the function to have a default value for .

Line 5 works as expected. On line 6, we are calling without passing any value to . Unlike the previous code snippet where was initialized with , in this example gets the default value as “JavaScript!”.

On line 7, we are calling by explicitly passing to parameter. Even then, JavaScript fills in the default value into .

So lines 6 and 7 are technically the same.

Line 8 is interesting as we are calling with . In this case, we are intentionally indicating to the JavaScript engine that we want an explicit empty value for . So JavaScript doesn’t fill in with the default value.

In summary, function parameters are initialized with the default values only when a parameter has a missing value or primitive value is passed in explicitly.

functions and return values

A JavaScript function can take zero or more inputs, and it can optionally return an output back to the function’s caller.

In the snippet below, lines 1 to 4 define a simplified function that takes two numbers and returns sum of those two numbers.

On line 5, we store the return value into and line 6 works as expected.

Lines 8 to 9 define the function that we have been using. Line 12 works as expected.

On line 14 we store the return value of the function call into .

But doesn’t have a . So what’s in then?

JavaScript returns by default when a function doesn’t return any other value. If a function returns explicitly, then is returned, not .

An empty statement is valid in JavaScript. So the following code returns as well.

encounters with undefined in the wild

There are a few places where you would encounter very often.

Non-existent properties on objects
In the snippet shown below, line 5 tries to access a non-existent property on the object. JavaScript fills in the missing property lookups with . Please note line 5 does not throw any error.

If you want to know if a property exists with as its explicitly assigned value vs. a property that doesn’t exist at all, prefer using the method from .

What if we tried ? Continue reading to know the answer.

Non-existent indexes in Arrays
In the snippet shown below, whenever we try to access an item at an array index that never had a value set, JavaScript treats us with the value.

object and array destructuring assignments
Object and array destructuring assignments work much like the above example.

enter the void
JavaScript has a unary operator which evaluates an expression and returns .

encounters with null in the wild

As we have already learned, JavaScript never implicitly initializes a value with . But here are a few places where you may encounter .

null in the prototype chain
All objects in JavaScript inherit from , which inherits the object.

regex matching
When a regular expression matching fails, it returns to indicate there were no matches found.

null is a keyword but undefined is not

is a keyword in JavaScript. So it can not be used for names.

The following code throws a on line 2.

Unlike , is not a keyword in JavaScript.

The following code works as expected, though you may be shaking your head in disbelief!

Also, the following code which runs in global context is allowed and it will not throw a . However, there is a nuance that we are going to see in the next section.

global object property named “undefined”

As if all this wasn’t already confusing enough, JavaScript has an named “undefined” on the whose value is primitive value .

In the above code snippet, in line 1 is being referenced like any other variable on the .

Line 2 is explicitly calling it on the object, which is an alias for the in the browser environment.

If only JavaScript stopped there! What happens when someone does the following?

to the rescue! Above line throws no errors and it has no effect when the code is running in . In , global gets the new value!

In most modern browsers with ECMAScript 5 support, global is a non-configurable, and non-writable property.

How not to test for

From the above example, we can conclude that “undefined” property on the is not reliable.

In normal conditions, the above code seems harmless. But this snippet can fail for either of the following two reasons:

  1. If the above code runs in the global scope, then the global “undefined” variable could have a wrong value in non-strict mode or in very old browsers.
  2. If the above code runs inside a local scope like a , then that scope can have an named “undefined” and it can contain a value other than the primitive value .

Then how do we test for ? Following sections, deep dive into this and a few other related topics.

Checking for non-existence?

What if we wanted to check if the already exists, and not create a new one if it does? Let’s try that out.

The above snippet throws a because a variable named doesn’t exist in any reachable scope.

So how do we solve this chicken-and-egg problem of creation then?

Luckily we have the operator to the rescue!

typeof operator and undefined

In short, operator returns the type of the expression it is applied to using the following syntax:

Returns a string value representing the type of the value that the expression is evaluated to. always returns a string.

A few examples using :

Now an interesting and often the most confusing part of operator is that it returns for any undeclared identifiers.

This is where a lot of confusion around stems from. operator, as invaluable as it is, doesn’t differentiate between a variable that’s never declared vs. a variable that’s declared but has as its value.

Ideally typeof should have returned something like when we used it on .

Going back to our original question of how we check for non-existence without running into , well, you know the answer now!

Unfortunately, there is no easy way to distinguish between an undeclared variable vs. a variable with no assigned value. We can employ a try/catch block, but it doesn’t look elegant.

More often than not, we don’t need to know if a variable is undeclared.

checking for null

Checking if a value is or not is very easy. One easy thing at last!

Please note the usage of which is a strict equality operator in JavaScript.

typeof operator and null

This is one of the most hated mistakes in the JavaScript language implementation.

operator on returns “object”. Ideally, it should have returned “null”.

So if you want to make sure something is an object, just checking for is not enough as it will be true for .

properties of undefined and null

Well, that was a trick heading! Don’t worry! There is nothing more to remember about and . You guessed it right! They don’t have any properties. One of the easiest things! Wasn’t it?

undefined and null in arithmetic operators

Let’s see a quick code snippet.

Why is it so? When JavaScript has to do type conversion on any value to a number, it follows an algorithm.

That algorithm states that must be converted to 0 while must be converted to NaN.

You can read more about it from the spec here:

quick closing thoughts

Ideally, we should strive for code that avoids explicit and values. But here are some closing thoughts.

Non-existent properties on object vs explicitly empty

In the above snippet, doesn’t even exist while exists with an value. When we use and , there is no easy to way distinguish between whether it exists or not. You will have to use or some other mechanism.

is explicitly set to . So we can always guarantee that it exists.

Same goes for as well.

function returning null
As we already learned, every function returns when no other value is returned from that function. If you really want to indicate that you are explicitly returning an empty or invalid value, then prefer returning .

Congratulations! Now you are an expert in using and ! Please share this article and clap if you enjoyed reading it.

For my day job @Salesforce, I write code for machines; But in my free time, I pursue this wild hobby of writing for humans. {Learn | Code | Read | Write}