Undefined vs. Null vs. Nullish
Level: Intermediate
Both undefined
and null
are used to represent variables or properties as having no value. undefined
is for properties which don’t exist or variables that have been declared but have not yet been defined, whereas null
is more for existing variables or properties that have been defined but point to no value (particularly object values). If a value is either undefined
or null
it is considered to be a “nullish” value.
Some syntax or APIs specifically check for these values but it may not always be clear when one or the other is being used or expected.
Loose Equality (==
)
When comparing either undefined
or null
with loose equality, only nullish values will evaluate to true. Any other comparison, even with other falsy values, will evaluate to false.
// checks for: nullish (for null and undefined)
null == null; // true
null == undefined; // true
undefined == null; // true
undefined == undefined; // true
null == false; // false
null == 0; // false
null == ''; // false
undefined == false; // false
undefined == 0; // false
undefined == ''; // false
Nullish Coalescing (??
)
As its name suggests, the nullish coalescing operator works with nullish values. If the left-hand side operator is nullish, the expression evaluates to what is on the right. This differs from logical or (||
) which checks for all falsy values.
// checks for: nullish
null ?? true; // true
undefined ?? true; // true
false ?? true; // false
0 ?? true; // 0
'' ?? true; // ''
Optional Chaining (?.
)
Like with nullish coalescing, optional chaining also relies on checking for nullish values. If nullish, the result of the expression will be undefined
(even if the original value was null
).
// checks for: nullish
null?.hasOwnProperty('foo'); // undefined
undefined?.hasOwnProperty('foo'); // undefined
false?.hasOwnProperty('foo'); // false
0?.hasOwnProperty('foo'); // false
''?.hasOwnProperty('foo'); // false
({ foo: 'foo' })?.hasOwnProperty('foo'); // true
Default this
Binding (Sloppy Mode)
In sloppy (non-strict) mode, when default this
binding is applied to a function, the value of this
in the function is the global object. This will happen when the function is called with any nullish context. Note: in strict mode, both null
and undefined
can be used to represent the this
value.
// checks for: nullish (non-strict)
function isGlobal () {
console.log(this === globalThis);
}
isGlobal.call(); // true
isGlobal.call(null); // true
isGlobal.call(undefined); // true
isGlobal.call({}); // false
isGlobal.call(true); // false
Default Parameters
Default parameters will be set only if the argument for that parameter was not provided (implicitly undefined
) or if explicitly set to the value undefined
.
// checks for: undefined
function defaults (param = true) {
console.log(param);
}
defaults(); // true
defaults(undefined); // true
defaults(null); // null
defaults(false); // false
defaults(0); // 0
Prototypes
Prototypes are objects which other objects inherit from. When at the end of a prototype chain, the prototype is null
. You cannot have an undefined
prototype.
// checks for: null
Object.create(null); // (Ok)
Object.create(undefined); // TypeError
Number Conversion
null
values can be successfully converted to a number, resulting in a 0 value. Converting undefined
results in NaN
. Note: parseInt()
/parseFloat()
will return NaN
for both undefined
and null
.
// checks for: null
console.log(Number(null)); // 0
console.log(+null); // 0
console.log(Number(undefined)); // NaN
console.log(+undefined); // NaN
More info:
- null on MDN
- undefined on MDN
- Loose equality (==) on MDN
- Nullish coalescing (??) on MDN
- Optional chaining (?.) on MDN
- Default parameters on MDN
- Object.create on MDN
- Number on MDN
More tips: JavaScript Tips of the Day