The Beginner's Guide to Null and Undefined in JavaScript

Many JavaScript developers, both junior and senior, often find themselves confused about the null and undefined types. This misunderstanding of the two types does not come without a cost: errors and bugs.

Before diving deeper, let’s first cover the basics:

undefined

undefined is returned if a variable was only declared but not assigned a value.

For example:

var ab

This will log undefined:

log(ab)

undefined variables are variables that are with no values. Let’s say the environment is represented like this:

environmentVariable = {
}

JS engine would interpret the VariableDeclaration var ab as:

environmentVariable = {
 ab: undefined
}

So when it is accessed the undefined will be returned. Now, when the ab is assigned a value:

ab = 90

The undefined will be changed to the value 90:

environmentVariable = {
 ab: 90
}

When we declared ab it was set in the environment variable table as undefined, meaning the value is on the way, now when we ab to value 90, the undefined was changed to 90. Now if we log ab it will no longer be undefined:

// ...
log(ab)
// 90

undefined can also occur if an object’s property doesn’t exist

let myDetails = {
 age: 27
}log(myDetails.name)
// undefined

or a function has a missing parameter:

function getMyDetails(a) {
 l(a)
}getMyDetails()
// undefined

undefined is a primitive data type in JS:

Boolean
Undefined
Number
String
Symbolvar ab
typeof ab
// undefined

You can check for the type using typeof keyword:

if(typeof ab == 'undefined') {
 // ...
}

undefined can be set explicitly:

var ab = undefined
l(ab)
// undefinedab = 90
l(ab)
// 90

null

null is a data type in JS that declares no value or non-existent value. null can be thought of as an intentional absence of any object value.

var ab = null
l(ab)
// null

Similarities

Let’s look at their similarities.

Both are falsy values

null and undefined always resolves to a falsy value. They are among the falsy values in JS:

  • null
  • undefined
  • false
  • 0
  • Empty string -> “”
  • NaN

If they are in the condition of an if-else statement, the else statement will always be executed:

if (null) {
 l('yes')
} else {
 l('no')
}

The above will log “no”.

if (undefined) {
 l('yes')
} else {
 l('no')
}

will also log “no”.

Both are primitive values

In JS we have Complex and Primitive data types, null and undefined are among the primitive data types:

Primitive data types are resolved by value-of-reference.

Differences

null and undefined means no-value but they resolve to diff. values:

l(typeof null)
// objectl(typeof undefined)
// undefined

You were expecting typeof null would return “null”? Right? This is a bug in JS for nearly two decades, but the thing is that it cannot be fixed. This is because thousands of websites depend on this buggy behavior, fixing it will make them break.

null is an assigned value, it must be explicitly assigned by the programmer. IF not assigned, the variable becomes undefined:

var ab = null
var a // undefined

unlike undefined which can be explicitly assigned or unassigned:

var ab = undefined
var bc l(ab)
// undefinedl(bc)
// undefined

Test for null

We saw that undefined resolves to “undefined” but null resolves to “object”.

We can easily test for undefined:

var abif(typeof ab == "undefined") {
 // ...
}

For null, we can’t do this:

var ab = nullif(typeof ab == "null") {
 // ...
}

typeof null returns “object” and we can be tempted to rewrite the above like this:

var ab = nullif(typeof ab == "object") {
 // ...
}

Many Complex data types return objects, the type can be checked via typeof:

let obj = {}
let arr = []
class D {}
const d = new D()l(typeof obj)
l(typeof arr)
l(typeof d)// object
// object
// object

So it would fail because an Array or Object might be the value of ab.

Now how do we correctly test for null, as null is a falsy value we will combine its check with the typeof check.

var ab = nullif(!ab && typeof ab == "object") {
 // ...
}

Abstract/Loose and Strict Equality on null and undefined

Let’s see what happens when strict and loose equality are performed on both types. But before that — a quick review of the loose equality specification:

7.2.14 Abstract Equality Comparison

The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is the same as Type(y), then a. Return the result of performing Strict Equality Comparison x === y.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ! ToNumber(y).
  5. If Type(x) is String and Type(y) is Number, return the result of the comparison ! ToNumber(x) == y.
  6. If Type(x) is Boolean, return the result of the comparison ! ToNumber(x) == y.
  7. If Type(y) is Boolean, return the result of the comparison x == ! ToNumber(y).
  8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
  10. Return false.

Look at 2 and 3

  1. If x is null and y is undefined, return true.
  2. If x is undefined and y is null, return true.

2 says if the LHS is null and the RHS is undefined, true is returned. This is why if we do this:

log(null == undefined)

it logs true

log(null == undefined)
// true

and says if the LHS is undefined and the RHS is null, it should also return true

log(undefined == null)
// true

This means that null and undefined are loosely equal, yes, it is understandable because they all represent an absence of no value, like in a key-value pair, the key is present but the value is not present/ is absent.

Let’s see about Strict Equality:

7.2.15 Strict Equality Comparison

The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:

  1. If Type(x) is different from Type(y), return false.
  2. If Type(x) is Number, then a. If x is NaN, return false. b. If y is NaN, return false. c. If x is the same Number value as y, return true. d. If x is +0 and y is -0, return true. e. If x is -0 and y is +0, return true. f. Return false.
  3. Return SameValueNonNumber(x, y).

looking at the above, strict equality returns false if the RHS and LHS types are different

Now, in the case of

null === undefined

This will be false because the types will be object and undefined, see they are different so it will return false.

log(null === undefined)

So,

null !== undefined

will be true. Why? It is because null => object is not the same type as undefined => undefined.

Understand this, The operator !== is asking whether the LHS is not strictly equal to RHS? So, in our case, yes(true) the LHS(null => object) is not strictly equal to the RHS(undefined => undefined).

null != undefined

This is asking if the LHS is not equal to the RHS. This is no, they are equal because Abstract Equality says to return true(that they are equal) if the LHS is either null or undefined and the RHS is either null or undefined.

Passing null and undefined as a function argument

We should be careful when declaring default argument value like this:

function defFunc(name = "nnamdi") {
 return name
}

This function just returns a name passed to it, see the argument name has a default value nnamdi, the argument will take nnamdi as value when the function is called with no parameters:

log(defFunc())
// nnamdi

It can be said like this, when the argument name is undefined it assumes the nnamdi value. So if we pass an undefined value to defFunc name will be nnamdi:

var ab
log(defFunc(ab))
// nnamdi

Now, what happens if we pass in null to the function? Do you think it will log nnamdi because null means the absence of a value or will it log null because null is a value? Let’s see:

log(defFunc(null))
// null

Wow!! it logged null. It should be because null is an object. I would say an empty object, yet still representing the absence of a value(s).

If you try to check for null argument, remember don;t do this:

function defFunc(name = "nnamdi") {
 if(typeof name == "null")
 return "nnamdi"
 return name
}

do this:

function defFunc(name = "nnamdi") {
 if(!name && typeof name == "object")
 return "nnamdi"
 return name
}

or you can delegate the null check to a function:

function isNull(val) {
 return !val && typeof val == "object"
}

you can use the isNull function anywhere in your program:

function defFunc(name = "nnamdi") {
 if(isNull(name))
 return "nnamdi"
 return name
}

Conclusion

I think we are clear on the disparities and similarities between null and undefined. So when next you see that error, you will know what to do.

Thanks !!!

#javascript

The Beginner's Guide to Null and Undefined in JavaScript
7.40 GEEK