null and undefined
Most languages have one "no value" placeholder. JavaScript has two: null and undefined. They mean almost the same thing in practice, but the language uses them differently and trips over its own legacy quirks (like typeof null being "object"). Knowing when each one shows up — and which operators treat them as a pair — keeps a whole category of bugs out of your code.
What each one means
undefinedis JavaScript saying "this slot exists but no value has been put here". It is the default for declared-but-unassigned variables, missing function arguments, missing object properties and explicitreturn;statements.nullis the developer saying "this slot exists and I deliberately set it to nothing". It is rarely produced by the engine — it appears when you assign it.
// Cases where JS gives you undefined
let x; // declared, not assigned -> undefined
function f(a) { return a; }
f(); // undefined — missing argument
const obj = { a: 1 };
obj.b; // undefined — missing property
function noReturn() {}
noReturn(); // undefined — implicit return
[1, 2, 3][99]; // undefined — out-of-range index
// Cases where you give it null
const user = { name: "Ada", manager: null }; // explicitly no manager
let selected = null; // "nothing selected yet"typeof null is "object" (a famous bug)
typeof undefined; // "undefined" typeof null; // "object" ← infamous // To check for null specifically: value === null; // To check for "either" null or undefined: value == null; // true for both null and undefined value === null || value === undefined;
The == null trick
== is mostly to be avoided, but there is one specific use that the entire JavaScript community has agreed to keep: x == null is shorthand for "is x either null or undefined?".
null == undefined; // true — only these two are == equal
null === undefined; // false
null == 0; // false — does NOT coerce to 0
undefined == ""; // false
function isNullish(v) {
return v == null; // succinct and idiomatic
}
isNullish(null); // true
isNullish(undefined); // true
isNullish(0); // false
isNullish(""); // falseNullish coalescing: ??
The ?? operator falls back only for null or undefined — not other falsy values. This makes it the right tool for "default value if missing":
const port = process.env.PORT ?? 3000; // undefined PORT -> 3000; "0" stays "0" const username = input ?? "guest"; // Compare with || which falls back on any falsy value: const wrong = 0 || 50; // 50 — but 0 was probably intentional const right = 0 ?? 50; // 0 — keeps the legitimate zero
Optional chaining: ?.
Closely related: ?. short-circuits to undefined instead of throwing when you reach for a property on null or undefined. Combine it with ?? for clean default chains.
const user = { profile: null };
// Old way — verbose
const city1 = user && user.profile && user.profile.address && user.profile.address.city;
// Modern way
const city2 = user?.profile?.address?.city;
// With a default
const city3 = user?.profile?.address?.city ?? "unknown";
// Also works on function calls and array indices
user.greet?.(); // call greet if it exists
arr?.[0]; // arr[0] if arr is not null/undefinedDefault parameters
Function parameter defaults are triggered only by undefined (not null). This matters more often than people expect.
function hello(name = "stranger") {
return `hello, ${name}`;
}
hello(); // "hello, stranger"
hello(undefined); // "hello, stranger"
hello(null); // "hello, null" — null is a real value!
hello(""); // "hello, " — empty string is real toohello, stranger hello, stranger hello, null hello,
Inside arrays and JSON
const arr = [1, , 3]; // sparse array, hole at index 1
arr.length; // 3
arr[1]; // undefined — but it's a "hole", subtle
JSON.stringify({ a: undefined, b: null });
// '{"b":null}' — undefined keys are dropped
JSON.stringify([undefined, null]);
// '[null,null]' — undefined inside arrays becomes null
JSON.parse('{"a": null}').a; // null
// JSON has no "undefined" — parsing never produces itWhen to use which — quick rules
Use
undefinedby omission: leave optional parameters out, don't set properties you don't have, return nothing for "no value yet".Use
nullby assignment: an intentional empty slot in a structured object, or "this lookup found nothing".Treat them as one concept in your code:
x == nullor the??/?.operators handle both at once.Don't use
typeof v === "undefined"unless you genuinely need to check whether a variable is declared. Otherwisev === undefinedis clearer.
The community has converged on a simple rule: write code that doesn't care whether a missing value is null or undefined. Use ?., ?? and == null, and you'll seldom be tripped up by the difference.