undefined
Learn where JavaScript creates undefined, how to tell it from missing names, and how defaults, JSON, void, and safe checks behave.
- 01Recognize every common sourcePredict when variables, properties, indexes, arguments, returns, Maps, and searches produce
undefined. - 02Separate absence from errorsExplain the difference between a declared value that is
undefined, a missing property, and a name that is not defined. - 03Use safe defaultsChoose
=== undefined,typeof,??,?., parameter defaults, destructuring defaults, and JSON behavior on purpose.
undefined in one sentence
undefined is JavaScript's value for “nothing has been put here yet.” It is both a value and its own primitive type: typeof undefined returns the string "undefined".
undefined means a variable, property, argument, return value, or lookup has no supplied value. It is a real value, not the same thing as a name that was never declared.
undefined exampleslet formField;var oldStyle;console.log(undefined);console.log(typeof undefined);console.log(formField);console.log(oldStyle);Lines 1 and 2 create declared bindings. Because neither has an initializer yet, lines 5 and 6 print undefined. Line 4 is different: it prints the type string, which happens to have the same letters.
const declaration must have a valueconst needsValue;let and old-style var can be uninitialized. const cannot. The hoisting lesson explains why var declarations also appear as undefined before assignment in classic scripts.
Imagine a row of lockers. One locker has your label but is empty: that is like a declared variable whose value is undefined. A locker number that does not exist is different: asking for it is closer to a ReferenceError.
- In real life: The locker exists and has your label
- In JavaScript: A declared variable or property name exists
- In real life: Nobody has put a bag inside yet
- In JavaScript: The value is
undefined - In real life: A locker number that is not on the wall
- In JavaScript: A name that is not defined at all
Where the analogy stops: A real empty locker is visible. JavaScript's undefined is a value used in several situations, and some missing paths throw errors instead.
Where JavaScript creates it
STEP THROUGHMost undefined values are not mistakes. They are JavaScript's normal answer when a value was not assigned, found, passed, or returned. Step through these origins one by one.
Walk through many ordinary origins of undefined: unfilled variables, absent object keys, sparse arrays, strings, Maps, empty arrays, and failed searches.
script
let oldCounter;const profile = { name: "Ada" };const tasks = ["learn"];const sparse = [1, , 3];const pantry = new Map([["tea", 2]]); console.log(draftTitle);console.log(oldCounter);console.log(profile.age);console.log(tasks[5]);console.log(sparse[1]);console.log("abc"[5]);console.log(tasks.at(-10));console.log(pantry.get("coffee"));console.log([].pop());console.log([1, 2].find((n) => n > 5));The replay includes uninitialized let and var, missing object properties, out-of-range indexes, an array hole, "abc"[5], arr.at(-10), Map#get for a missing key, [].pop(), and find with no match.
Missing properties, indexes, and holes
Reading a missing property is safe when the object itself exists. Reading through a missing middle value is not safe. A sparse array hole also reads as undefined, but it is not the same as a stored value.
undefinedconst user = { name: "Ada" };const scores = [10, 20];const sparse = [1, , 3]; console.log(user.age);console.log(scores[5]);console.log(sparse[1]);console.log(1 in sparse);console.log("abc"[5]);console.log(scores.at(-10));The 1 in sparse line prints false, proving index 1 is a hole rather than a present element. The read still gives undefined.
const user = {};console.log(user.address.city);Use optional chaining, such as user?.address?.city, when each step might be missing and the safe result should be undefined instead of a TypeError.
Arguments and return values
STEP THROUGHFunction parameters are local variables. If a call supplies fewer arguments than the function names, the extra parameters start as undefined. A function with no returned value also produces undefined.
Call the same function with all arguments, fewer arguments, explicit undefined, and null. Watch when the default parameter runs.
script
function greet(name = "friend", punctuation = "!") { return "Hello, " + name + punctuation;} console.log(greet());console.log(greet(undefined, "?"));console.log(greet(null));Defaults run only when the argument is missing or explicitly undefined. Passing null is different: it is a value, so the default does not run. The later comparison lesson Booleans, null & undefined puts that side by side with null.
undefinedfunction showArgument(value) { console.log(value);}function noReturn() { const status = "saved";}function bareReturn() { return;} showArgument();console.log(noReturn());console.log(bareReturn());const printed = console.log("console.log prints first");console.log(printed);console.log([1, 2].forEach((n) => n * 2));console.log([1, 2].find((n) => n > 5));console.log(new Map().get("missing"));console.log([].pop());Line 14 proves a subtle point: console.log prints its message and then returns undefined. forEach is similar: it runs a callback for side effects and returns undefined.
undefined vs not defined
undefined means a binding exists and currently holds the undefined value. Not defined means JavaScript cannot find a binding for the name at all.
typeoflet declared;console.log(declared);console.log(typeof declared);console.log(typeof neverDeclared);The special typeof neverDeclared form returns the string "undefined" without throwing. That makes it useful for guarded checks around globals that may not exist.
console.log(neverDeclared);Checking and defaults
For a declared value, value === undefined is the direct check. For a name that might not exist, use typeof name === "undefined". For fallbacks, prefer ?? and ?. when 0, false, or "" should stay valid.
undefined is not missingconst present = { key: undefined };const missing = {}; console.log("key" in present);console.log("key" in missing);console.log(Object.hasOwn(present, "key"));console.log(Object.hasOwn(missing, "key"));console.log(Object.keys(present).join(","));console.log(JSON.stringify(present));A key can be present while its value is undefined. "key" in obj, Object.hasOwn, and Object.keys answer whether the property exists; reading obj.key answers what value is stored there.
undefinedfunction greet(name = "friend") { console.log("Hello, " + name);}greet(undefined);greet(null); const [first = "fallback", second = "backup"] = [undefined, null];const { label = "Untitled", count = 0 } = { count: undefined };console.log(first);console.log(second);console.log(label);console.log(count);Parameter defaults and destructuring defaults use the fallback for undefined. They do not replace null, because null is an explicit value.
void and the global value
The void operator evaluates an expression and always produces undefined. The global undefined property is read-only and non-configurable in modern JavaScript.
void and the global descriptorconst descriptor = Object.getOwnPropertyDescriptor(globalThis, "undefined");console.log(descriptor.writable);console.log(descriptor.configurable);console.log(void 0);console.log(void "hello");Since ES5, globalThis.undefined is non-writable and non-configurable. Assigning to it in sloppy code does nothing; assigning in strict mode throws a TypeError.
undefined = "changed";console.log(undefined);"use strict";undefined = "changed";A local scope can technically shadow the name undefined, but never do that in real code. It makes examples harder to read and fights a value JavaScript already gives you. The engine details live in undefined inside the engine.
Operations and JSON
undefined is falsy, but operations still have exact conversion rules. Arithmetic turns it into NaN. String contexts print the word undefined. JSON treats it differently depending on where it appears.
console.log(undefined + 1);console.log(`value: ${undefined}`);console.log(String(undefined));console.log(Number(undefined));console.log(undefined == null);console.log(undefined === null);console.log(JSON.stringify({ a: undefined }));console.log(JSON.stringify([undefined]));console.log(JSON.stringify(undefined));The last line is the surprise: JSON.stringify(undefined) returns the undefined value itself, not a string. In objects, undefined properties are omitted; in arrays, undefined entries become null to preserve the slot.
Try real expressions
PLAYGROUNDPick a tiny program and compare the value, the type, and the console output. Some choices return undefined; one deliberately throws because a middle property is missing.
let x;console.log(x);A declared variable without an initializer starts with the undefined value.
let x; x produces undefined with typeof undefined. Console output: undefined. A declared variable without an initializer starts with the undefined value.
Sort the outcomes
SORTERSimilar-looking expressions can produce undefined, null, an error, or a different value entirely. Sort the cards by what JavaScript actually does.
({}).xnull.xneverDeclared[].pop()"abc"[5]"abc".match(/z/)JSON.parse("null")typeof neverDeclarednew Map().get("k")[1, 2].find((n) => n > 5)(() => {})()void "hi"[1, , 3][1]({ a: null }).aJSON.stringify(undefined)({})?.address?.city
Place each expression in the category for its actual result.
Practical patterns
Real projects meet undefined in options objects, optional function parameters, and API responses with missing fields. The safe pattern is to read carefully, default narrowly, and keep valid falsy values.
function connect(options = {}) { const retries = options.retries ?? 3; return "retries: " + retries;} const apiUser = { profile: { name: "Ada" } };console.log(connect({ retries: 0 }));console.log(connect({}));console.log(apiUser.profile?.address?.city ?? "Unknown city");- Use
options =so callers may omit the whole options object. - Use
??so0stays a real setting. - Use
?.before optional API fields that may be missing. - When an API must say “deliberately empty,” expect
nulland link to the null lesson.
Common misconceptions
- “undefined means the variable does not exist.” No. A declared variable can hold
undefined; an undeclared name throws when read. - “A missing property and a missing middle object behave the same.” No.
obj.missingis safe;obj.missing.xthrows. - “Array holes store
undefined.” A hole is absent. Reading it producesundefined, butindex in arrayis false. - “Defaults replace
null.” Defaults replace onlyundefinedand missing arguments or properties. - “JSON has an
undefinedvalue.” JSON hasnull, but noundefinedliteral.
| Situation | Setup | Reading and typeof | Presence checks | JSON result |
|---|---|---|---|---|
| Declared but no value | let x; | typeof x is "undefined"; reading x gives undefined | No object key unless you store one | JSON.stringify({ x }) becomes {} |
| Missing property | const obj = {}; obj.x | typeof obj.x is "undefined"; reading it gives undefined | "x" in obj is false | JSON.stringify(obj) is {} |
Present with value undefined | { x: undefined } | Reading obj.x gives undefined | "x" in obj and Object.hasOwn(obj, "x") are true | JSON omits the property |
| Not declared | neverDeclared | typeof neverDeclared is the string "undefined", but reading it throws ReferenceError | It is not a binding you can check with in | You cannot serialize a name that cannot be read |
Practice exercises
6 EXERCISESPredict the three console lines in order.
let x;
const obj = {};
console.log(x);
console.log(obj.missing);
console.log([1][1]);All three lines print undefined: an uninitialized variable, a missing object property, and a missing array slot.
Predict what the two calls print.
function label(value = "fallback") {
return value;
}
console.log(label(undefined));
console.log(label(null));The first call prints fallback. The second prints null because defaults do not replace null.
Predict the two presence checks.
const settings = { theme: undefined };
console.log("theme" in settings);
console.log("mode" in settings);"theme" in settings is true. "mode" in settings is false.
What exact city text prints?
const user = { profile: {} };
const city = user.profile?.address?.city ?? "Unknown";
console.log(city);const user = { profile: {} };
const city = user.profile?.address?.city ?? "Unknown";
console.log(city);The optional chain returns undefined, then ?? replaces it with Unknown.
Predict the three JSON outputs.
console.log(JSON.stringify({ a: undefined }));
console.log(JSON.stringify([undefined]));
console.log(JSON.stringify(undefined));The outputs are {}, [null], and undefined in that order.
Which operator makes this guard safe even though maybeName was never declared?
if (typeof maybeName === "undefined") {
console.log("safe");
}if (typeof maybeName === "undefined") {
console.log("safe");
}Use typeof. It can inspect a name that might not be declared and returns the string "undefined".
Check your understanding
8 QUESTIONSQuestion 1 of 8What does
typeof undefinedreturn?Read the code, then predictconsole.log(typeof undefined);Choose an answer to see the explanation.
Question 2 of 8What does an uninitialized
letprint?Read the code, then predictlet draft; console.log(draft);Choose an answer to see the explanation.
Question 3 of 8What happens here?
Read the code, then predictconst user = {}; console.log(user.address.city);Choose an answer to see the explanation.
Question 4 of 8Which expression is safe for a name that might not be declared?
Choose an answer to see the explanation.
Question 5 of 8Which calls use the default parameter?
Read the code, then predictfunction greet(name = "friend") { console.log(name); } greet(undefined); greet(null);Choose an answer to see the explanation.
Question 6 of 8What does
void "hi"produce?Read the code, then predictconsole.log(void "hi");Choose an answer to see the explanation.
Question 7 of 8What do these comparisons print?
Read the code, then predictconsole.log(undefined == null); console.log(undefined === null);Choose an answer to see the explanation.
Question 8 of 8How does JSON handle
undefined?Read the code, then predictconsole.log(JSON.stringify({ a: undefined })); console.log(JSON.stringify([undefined])); console.log(JSON.stringify(undefined));Choose an answer to see the explanation.
Key takeaways
undefinedis both a primitive value and the result oftypeof undefined.- It appears when values are declared but unfilled, looked up but absent, not passed, or not returned.
- Reading an undeclared name is a ReferenceError;
typeof neverDeclaredis the safe exception. - Defaults and destructuring fallbacks run for
undefined, not fornull. - Use
?.,??,Object.hasOwn, and JSON rules deliberately instead of guessing from truthiness.
Final definition: undefined is JavaScript's built-in value and type for a place that exists but has no supplied value.
Up next: null, the value you put in code when “nothing here” is intentional.