Problem Solved

JavaScript · null vs undefined

Home › Courses › JavaScript › Problems › null vs undefined
🟨 Concept · 3 min read

null vs undefined.
Two nothings. Different meanings.

Both mean "no value." But they mean it differently. undefined is JavaScript's default — a variable that was never assigned, a missing argument, an absent property. null is your default — a value you set explicitly to mean "nothing here." One is automatic, the other is intentional. This page covers the difference, the check patterns, the typeof null quirk, and why ?? is almost always better than ||.

Short answer: undefined = not assigned by JavaScript. null = explicitly set to "nothing" by you. Check for both with value == null (the one accepted use of ==). Check for null specifically with value === null. typeof null === 'object' is a historical bug — don't rely on typeof to detect null. Use ?? (nullish coalescing) for defaults — it only triggers on null/undefined, not 0 or ''.

✅ When each appears

JavaScript gives you undefined. You give null.

undefined (automatic)

Uninitialized variable. Missing function argument. Non-existent property. Function with no return. Array index out of bounds.

null (intentional)

const user = null; — "no user yet." document.getElementById('missing') returns null. JSON null parses to null.

Both are falsy

if (value) skips both. value ? a : b treats both as false. !value is true for both.

Both are primitives

typeof undefined === 'undefined'. typeof null === 'object' (historical bug).

✅ When each appears in practice

The sources of both values.

null-undefined-sources.js
// === undefined sources ===

let a;                    // never assigned
console.log(a);           // undefined

function f(x) { return x; }
console.log(f());         // undefined (missing arg)

const obj = {};
console.log(obj.missing); // undefined (no property)

function g() {}
console.log(g());         // undefined (no return)

const arr = [1, 2, 3];
console.log(arr[99]);     // undefined (out of range)

// === null sources ===

const user = null;        // explicit "nothing"
console.log(user);        // null

const el = document.getElementById('does-not-exist');
console.log(el);          // null

const data = JSON.parse('{"a": null}');
console.log(data.a);      // null (JSON null)
Summary:

undefined is JavaScript's default:
  → variables not yet assigned
  → missing function arguments
  → missing object properties
  → functions without a return
  → array indices out of bounds
  → the value of 'delete obj.prop'

null is always explicit:
  → you write null in your code
  → some DOM APIs return null
  → JSON.parse produces null for JSON null
  → some APIs return null (databases, fetch)

You rarely write null in JS.
You frequently receive null from APIs.
And you frequently encounter undefined
from your own code.

Both are "empty," but the source differs.

✅ How to check for them

The three patterns, and which to use when.

null-checks.js
const v1 = null;
const v2 = undefined;
const v3 = 0;
const v4 = '';
const v5 = false;

// Check for EITHER null or undefined
console.log(v1 == null);   // true
console.log(v2 == null);   // true
console.log(v3 == null);   // false
console.log(v4 == null);   // false
console.log(v5 == null);   // false

// Check for ONLY null
console.log(v1 === null);  // true
console.log(v2 === null);  // false

// Check for ONLY undefined
console.log(v2 === undefined);  // true
console.log(v1 === undefined);  // false

// Check for existence (variable may not exist)
console.log(typeof undeclaredVar === 'undefined');  // true (no error)

// Modern default — nullish coalescing
console.log(v1 ?? 'default');  // 'default'
console.log(v3 ?? 'default');  // 0 (not nullish)
Pattern 1: value == null
  → true for null AND undefined
  → false for 0, '', false, NaN, {}, []
  → the one accepted use of ==
  → use for: "is this value missing?"

Pattern 2: value === null
  → true only for null
  → use for: "was this explicitly set to nothing?"

Pattern 3: value === undefined
  → true only for undefined
  → use for: "was this never assigned?"
  → WARNING: if the variable doesn't exist,
    this throws ReferenceError

Pattern 4: typeof value === 'undefined'
  → true if the variable doesn't exist OR is undefined
  → use for: existence checks (no ReferenceError)

Pattern 5: value ?? 'default'
  → returns 'default' only if value is null or undefined
  → unlike ||, doesn't trigger on 0, '', false
  → use for: defaults (almost always correct)

Which to use:

  "Is this null or undefined?" → value == null
  "Is this specifically null?"  → value === null
  "Does this variable exist?"   → typeof value !== 'undefined'
  "Default if missing?"         → value ?? fallback

✅ The ?? vs || distinction

Why ?? is almost always the right default.

nullish-coalescing.js
// The problem with ||
function getCount(value) {
  return value || 10;
}

console.log(getCount(0));    // 10 — WRONG. 0 is valid.
console.log(getCount(''));   // 10 — WRONG. '' might be valid.
console.log(getCount(false)); // 10 — WRONG. false is valid.
console.log(getCount(null));  // 10 — correct
console.log(getCount(undefined)); // 10 — correct

// The fix: ??
function getCountFixed(value) {
  return value ?? 10;
}

console.log(getCountFixed(0));    // 0  — correct
console.log(getCountFixed(''));   // '' — correct
console.log(getCountFixed(false)); // false — correct
console.log(getCountFixed(null));  // 10 — correct
console.log(getCountFixed(undefined)); // 10 — correct
|| triggers on ANY falsy value:
  0, '', false, NaN, null, undefined

?? triggers ONLY on nullish values:
  null, undefined

This matters when 0, '', or false are
valid values:

❌ || for default count → returns 10 when 0
✅ ?? for default count → returns 0 when 0

❌ || for default price → returns 10 when 0
✅ ?? for default price → returns 0 when 0

❌ || for default enabled → returns true when false
✅ ?? for default enabled → returns false when false

Rule: use ?? for defaults, unless you
specifically want to replace all falsy values.

The most common bug: "0 becomes the default."
It happens because 0 is falsy. ?? fixes it.

Modern JavaScript code uses ?? almost exclusively
for defaults. || is reserved for cases where
you genuinely want to replace any falsy value
(rare).

Don't use typeof to check for null. typeof null === 'object' is a historical bug that can't be fixed without breaking the web. If you write if (typeof value === 'object') expecting to detect an object, null passes the test. The fix: check for null explicitly with value === null, or check value !== null && typeof value === 'object'. This is one of the most common typeof pitfalls. Use === for primitives, typeof only for distinguishing between types where the bug doesn't matter (like checking whether a variable exists).

⚠️ Common mistakes

The null/undefined mistakes that cost real time.

1. Using typeof to check for null

typeof null === 'object'. Fix: value === null.

2. Using || for defaults

Replaces 0, '', false. Fix: ??.

3. Not checking for undefined before accessing properties

obj.foo.bar throws if foo is undefined. Fix: obj.foo?.bar.

4. Assuming null and undefined are equal

null === undefined is false. Fix: value == null for both.

5. Setting variables to undefined

Use null to explicitly clear. Fix: value = null.

6. Comparing with == against other values

value == '' is true for 0 too. Fix: use === for everything except null checks.

7. Using typeof for existence checks

Ok — but doesn't catch null. Fix: combine with !== null.

8. Sending undefined to JSON.stringify

undefined properties are dropped, null are kept. Fix: use null for explicit "nothing" in JSON.

❓ Frequently asked

What is the difference between null and undefined?

undefined means a value was never assigned — it's the default for uninitialized variables, missing function arguments, and missing object properties. null is an intentional absence — a value you assign explicitly to mean 'no value.' undefined is set by JavaScript; null is set by you. Both are falsy, both are primitives, and both are usually checked with the same pattern.

Should I use null or undefined?

Use undefined for 'not yet set' — leave the default. Use null when you need to explicitly clear a value. In practice, most modern code uses undefined as the default and null only when interfacing with APIs that return null. The pragmatic rule: don't worry about it much — the important thing is to handle both when checking.

How do I check for null or undefined?

The shorthand: value == null is true for both null and undefined, false for everything else. This is the only widely accepted use of ==. The explicit version: value === null || value === undefined. Both work. For null specifically: value === null. For undefined specifically: value === undefined. Use the right check for the case.

Is undefined the same as not defined?

No. 'Not defined' means the variable doesn't exist — accessing it throws a ReferenceError. 'undefined' means the variable exists but has no value. The typeof operator is the safe check: typeof x === 'undefined' works whether x exists or not. Just x === undefined throws if x was never declared.

What is nullish coalescing (??)?

?? is the nullish coalescing operator. a ?? b returns a if a is NOT null and NOT undefined, otherwise returns b. It's like || but only triggers on null/undefined, not on 0, '', false, or NaN. Use ?? when you only want to replace null/undefined. Use || when you want to replace any falsy value.

Why does typeof null return 'object'?

It's a bug in the original JavaScript implementation, and it can't be fixed without breaking the web. In the first version, values were represented with a type tag. Objects had type tag 0, and null was represented as a null pointer (all zeros), which has type tag 0. So typeof null === 'object'. To check for null, use value === null, not typeof.

🔗 Continue learning

🗺️ JavaScript learning path
The full roadmap from variables to async — every concept in order

Next in this series:

🔗 Optional chaining
Safe property access — and why it's not a substitute for validation
← All JavaScript problems
Problem solved · JavaScript