Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

JavaScript WTF #4: Undefined vs Null

4.89/5 (8 votes)
31 Dec 2016Apache2 min read 14.2K  
JavaScript WTF #4: Undefined vs Null

The forth place in the JavaScript WTF competition goes to the amazingly large number of ways to represent lack of value. Most C-like languages have keyword null that means “no value”. Beside null, JavaScript also has undefined, apparently meaning “like, totally no value”. The actual situation is even more complicated. A variable in JavaScript can be in any of the following states of no-value-ness:

  1. Not declared
  2. Not initialized or explicitly set to undefined
  3. Explicitly set to null
  4. Temporarily dead (this is not a joke)

There is an impressive number of subtle differences between these states.

Not Declared

In default, non-strict mode, not declared variables are treated as not initialized, and have implicit value of undefined. In strict mode, accessing a not declared variable causes a ReferenceError, except when used with typeof.

JavaScript
'use strict';
console.log(typeof notDeclared==="undefined"); // prints true
console.log(notDeclared===undefined);                    // ReferenceError

Note that typeof notDeclared returns string "undefined", which is different from undefined value.

Not Initialized

Declared, but not initialized variables are implicitly assigned a value of undefined. There is no way to distinguish between a variable that was never initialized, and a variable that was explicitly set to undefined.

JavaScript
var notInitialized;
console.log(typeof notInitialized==="undefined"); // true
console.log(notInitialized===undefined);                    // true

Null

Null is interpreted as pointing to no object. It is different from undefined in a number of ways:

JavaScript
var nullVar = null;

console.log(typeof nullVar === "object"); // true
console.log(nullVar === null);                      // true
console.log(nullVar === undefined);                 // false
console.log(nullVar == undefined);                  // true
console.log(1+null);                                // 1
console.log(1+undefined);                           // NaN

An attempt to access any property of null or undefined leads to ReferenceError. One can check for null or undefined in one shot using equality operator “==”:

JavaScript
if (someVar == null) ... // true if someVar is undefined or null

However, simply writing if (!someVar) is not recommended: the condition will be true not only for null and undefined, but also for false, the number 0, the empty string "" and Number.NaN.

Dead

Temporarily dead variables are an addition of EcmaScript6: these are variables declared via let or const keywords in the lines preceding their declaration:

JavaScript
function foo() {
   // x is in a "temporarily dead zone" (TDZ) here
   let x; 
   // x has value of undefined here
}

“Normal” variables are “hoisted” to the top of their scope, but “let” and “const” variables are not. Any access to a let or const variable prior to its declaration is not allowed. This includes the typeof operator.

JavaScript
console.log(declaredLater===undefined);                  // true
console.log(typeof notDeclared==="undefined"); // true
console.log(typeof dead);                                // ReferenceError
var declaredLater = 42;
let dead;

Conclusion

To be fair, there are situations when it helps to distinguish “a value of null” and “no value at all”. E.g. when sending partial updates, null may mean “replace this field with null” and undefined may mean “do not touch”. When dealing with default function parameters: undefined means “use default value”, and null means “use null”. In the old days of COM, we had VT_NULL, VT_EMPTY, and also vtMissing, which actually is a third, different value.

Still, JavaScript situation is a mess. The differences between the four “no-value” states are not intuitive, to put it mildly, and there are no explicit checks for them. I wish we had something like isDeclared(symbol), and isInTdz(symbol), but alas: the best we can do is to rely on confusing side-effects. Hence, the WTF.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0