undefined
Learn where JavaScript creates undefined, how to tell it from missing names, and how defaults, JSON, void, and safe checks behave.
- 01Know where it comes fromPredict when a variable, a property, an index, an argument, a function result, a Map, or a search gives
undefined. - 02Tell it apart from an errorExplain the difference between a variable that holds
undefined, a property that is not there, and a name that was never created. - 03Choose safe checks and defaultsPick the right tool on purpose:
=== undefined,typeof,??,?., default values, and the JSON rules.
Watch the video lecture
Full course on YouTube (opens in a new tab) ↗- Lecture 17undefined, explainedWatch on YouTube (opens in a new tab) ↗
What undefined means
undefined is a value. JavaScript uses it to mean "nothing has been put here yet." It is also its own type. The typeof operator tells you the type of a value, as text. So typeof undefined gives the text "undefined".
undefined is the value you get when a place exists but nothing was put in it. The place can be a variable, a property, an argument, or the result of a function. It is a real value. It is not the same as a name that was never created.
undefinedlet formField;var oldStyle;console.log(undefined);console.log(typeof undefined);console.log(formField);console.log(oldStyle);Lines 1 and 2 create two variables, formField and oldStyle. Neither one gets a value. So lines 5 and 6 print undefined. Line 3 prints the value undefined itself. Line 4 is different. It prints the type, which is the text "undefined". The console shows the same word for both.
const must get a value right awayconst needsValue;let and the older var can start with no value. const cannot. A const must get its value on the same line. Without one, you get a SyntaxError: JavaScript refuses to run the code at all.
The hoisting lesson explains one more case. In classic scripts, a var reads as undefined even before the line that gives it a value.
Picture a row of lockers. One locker has your name on it, but it is empty. That is like a variable whose value is undefined. Now picture asking for a locker number that is not on the wall at all. That is like reading a name that was never created. JavaScript throws a ReferenceError.
- In real life: The locker is there, with your name on it
- In JavaScript: A variable or property exists
- In real life: Nobody has put a bag inside yet
- In JavaScript: Its value is
undefined - In real life: A locker number that is not on the wall
- In JavaScript: A name that was never created
Where undefined comes from
STEP THROUGHMost undefined values are not mistakes. JavaScript gives you undefined when nothing was:
- put into a variable,
- found at a property or an index,
- passed in as an argument, or
- returned from a function.
Below, you can step through these cases one at a time.
undefinedfunction greet(name) { console.log(name);}greet();Line 1 makes a function, greet, with one parameter, name. A parameter is a variable that holds what the caller passes in. Line 4 calls greet but passes nothing. So on line 2, name is undefined. The function still runs. It just has no name to print.
Step through everyday ways to get undefined: empty variables, missing keys, array holes, strings, Maps, empty arrays, and searches that find nothing.
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 step-through shows each of these reads giving undefined:
- Two variables that never got a value (lines 8 and 9).
- A property the object does not have,
profile.age(line 10). - An index past the end of an array,
tasks[5](line 11). - A hole in an array,
sparse[1](line 12). The next section explains holes. - An index past the end of a string,
"abc"[5](line 13). tasks.at(-10)(line 14). With a negative number,atcounts back from the end. Here it goes past the start.- A key that a Map does not have,
pantry.get("coffee")(line 15). A Map is a list of keys and values, andgetlooks up one key. [].pop()(line 16).popremoves the last item, but an empty array has none.findwith no match (line 17).findreturns the first item that passes the test. Here, no item does.
Missing properties, indexes, and holes
Reading a property that an object does not have is safe. You get undefined. But when a value in the middle of a chain like user.address.city is missing, the next read fails.
Arrays can also have holes. A hole is an empty spot with no item at all. Reading a hole gives undefined too, but nothing is stored there.
const 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));Lines 5, 6, 7, 9, and 10 all print undefined. Line 7 reads the hole in sparse. Line 8 checks that spot with the in operator. in asks, "Is there an item at this index?" It prints false. So index 1 is a hole, not a stored value, even though reading it gives undefined.
const user = {};console.log(user.address.city);user.address: the cart is there, but it has no address, so you get undefined. Then JavaScript tries to read .city from undefined. There is nothing to read from, so it throws a TypeError.When a step might be missing, use optional chaining, written ?.. If the value on its left is undefined or null, it stops and gives undefined instead of throwing. For example, user?.address?.city gives undefined here, not a TypeError.
?. and ?? for a city that is not thereconst user = { profile: {} };console.log(user.profile?.city);console.log(user.profile?.city ?? "Unknown");Line 2 reads city, which profile does not have, so it prints undefined. Line 3 adds ??. It gives the value on its right when the left side is undefined or null. So the missing city becomes the text "Unknown".
Arguments and return values
STEP THROUGHA function's parameters are variables inside the function. If a call passes fewer arguments than there are parameters, the extra parameters start as undefined. A function that returns nothing also gives back undefined.
The step-through below uses default parameters. In name = "friend", the value after = is used when no argument comes in.
Call the same function four ways: with an argument, with none, with undefined, and with null. Watch when the default is used.
script
function greet(name = "friend", punctuation = "!") { return "Hello, " + name + punctuation;} console.log(greet());console.log(greet(undefined, "?"));console.log(greet(null));A default is used only when the argument is missing or is undefined. Passing null is different. null is a real value that someone chose, so the default is not used. The later lesson Booleans, null & undefined compares null and undefined side by side.
function greet(name = "friend"). When the argument is undefined, the default "friend" goes into the box. When the argument is null, null goes into the box, and the default is not used.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 11 passes no argument, so
valueisundefined. - Line 12 calls a function that has no
return. - Line 13 calls a function with an empty
return;. - Lines 14 and 15 show a surprise.
console.logprints its message, and then it returnsundefined. - Line 16 is similar.
forEachruns a function once for each item, for the work it does. It returnsundefined. - Lines 17 to 19 are lookups that find nothing.
const result = console.log("saved");console.log(result);Line 1 prints "saved" right away. Then it stores what console.log returned in result. Line 2 prints result. So the output is saved, then undefined.
undefined vs not defined
These two sound alike, but they mean different things:
undefined: the variable exists, and its value isundefined.- Not defined: JavaScript cannot find any variable with that name.
let declared;console.log(declared);console.log(typeof declared);console.log(typeof neverDeclared);Line 2 reads declared. It exists, so it prints undefined. Line 3 prints its type, the text "undefined".
Line 4 uses typeof on neverDeclared, a name that was never created. typeof has a special rule for this. It gives the text "undefined" instead of throwing. So it is a safe way to check for a name that might not exist.
console.log(neverDeclared);Without typeof, reading neverDeclared throws a ReferenceError. That error means "there is no variable with this name."
let declared; makes a box with nothing put in it yet, so reading it gives undefined. Nobody ever made a box called neverDeclared, so there is nothing to read, and JavaScript throws a ReferenceError.Checking and defaults
Pick the check that fits your question:
- Is this variable
undefined? Usevalue === undefined. The===operator checks that two values are exactly the same. - Does this name exist at all? Use
typeof name === "undefined". - Do you need a fallback value? Use
??and?.. They keep0,false, and""(the empty string) as real values.
undefinedconst 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));Line 1 makes an object with a key, key, whose value is undefined. Line 2 makes an empty object. Reading key from either one gives undefined. To tell them apart, ask whether the key exists:
"key" in obj(lines 4 and 5).Object.hasOwn(obj, "key")(lines 6 and 7).Object.keys(obj), which lists the keys (line 8).
Line 9 shows that JSON leaves the key out. The JSON section below explains why.
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);Lines 4 and 5 call greet with undefined, then with null. Only the first call uses the default.
Lines 7 and 8 use destructuring: pulling values out of an array or an object into variables. A default after = works the same way there:
firstgets"fallback", because its value isundefined.secondkeepsnull.labelgets"Untitled", because the object has nolabel.countgets0, because the object'scountisundefined.
?? when 0 or an empty string is a real valueconst savedItems = 0;const nickname = "";console.log(savedItems ?? 3);console.log(savedItems || 3);console.log(nickname ?? "Guest");console.log(nickname || "Guest");Lines 3 and 5 use ??. It keeps 0 and the empty string, because it only replaces null or undefined.
Lines 4 and 6 use || (OR). It replaces any falsy value. A falsy value is one that if treats as false, such as 0 and "". So || throws away the real 0 and gives 3.
void and the global undefined
The void operator runs the expression after it, throws away the result, and gives undefined.
JavaScript also has a global property named undefined that holds this value. Global means you can use it anywhere. You cannot change it, and you cannot delete it.
void, and the settings of the global undefinedconst descriptor = Object.getOwnPropertyDescriptor(globalThis, "undefined");console.log(descriptor.writable);console.log(descriptor.configurable);console.log(void 0);console.log(void "hello");- Line 1 asks JavaScript for the settings of the global
undefinedproperty. - Line 2 prints
false: you cannot write a new value into it. - Line 3 prints
false: you cannot delete it or change its settings. - Lines 4 and 5 show that
voidalways givesundefined.
These settings have been in place since ES5, the 2009 version of JavaScript. Now see what happens when code tries to change the value.
undefined = "changed";console.log(undefined);"use strict";undefined = "changed";Strict mode is a stricter way to run JavaScript. You turn it on with "use strict" at the top. Without it, line 1 of the first block quietly does nothing, so line 2 still prints undefined. With it, the same change throws a TypeError.
Inside a function, you could make your own variable named undefined. Never do that. It makes code confusing, and JavaScript already gives you the real value. To see how the engine stores undefined, read undefined inside the engine.
undefined in math, text, and JSON
undefined is falsy, so if treats it as false. Other operations have their own rules:
- In math, it becomes
NaN, which means "not a number". - In text, it becomes the word
undefined. - In JSON, the result depends on where it is.
undefined in math, text, comparisons, and JSONconsole.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));- Lines 1 and 4 give
NaN. - Lines 2 and 3 give the text
undefined. - Line 5 uses loose equality,
==. It countsnullandundefinedas equal, so it printstrue. - Line 6 uses strict equality,
===. It does not count them as equal, so it printsfalse. - Lines 7 to 9 use
JSON.stringify. It turns a value into JSON text. JSON is the text format web apps use to send data.
undefined, so JSON.stringify does one of three things. In an object, it leaves the key out. In an array, it writes null so the array keeps its length. On its own, it gives back undefined, not a string.The last line is the surprise. JSON.stringify(undefined) does not give a string at all. It gives back the value undefined.
Try small programs
PLAYGROUNDPick a small program from the list. Then compare three things: the value, its type, and what the console prints. Most programs give undefined. One throws on purpose, because a value in the middle of a chain is missing.
let x;console.log(x);The variable exists, but nothing was put in it, so it holds undefined.
let x; x gives undefined. Its type is undefined. The console prints: undefined. The variable exists, but nothing was put in it, so it holds undefined.
Sort the outcomes
SORTERSome expressions look alike but give different results: undefined, null, an error, or something else. Sort each card by what JavaScript really 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
Put each expression in the group for its real result.
Where you meet undefined in real code
In real projects, undefined often shows up in three places:
- settings objects, where the caller leaves some settings out,
- function parameters that the caller may skip, and
- data from a server (an API) where a field is missing.
The safe way is to read with care, use a fallback only for undefined or null, and keep real values like 0.
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");- Line 1 gives
optionsa default,{}, an empty object. So a caller can leave out the whole settings object. - Line 2 uses
??. So on line 7,retries: 0stays0. - Line 8 passes no
retries, so the fallback,3, is used. - Line 9 reads a city that is not there and prints
"Unknown city".
Keep these habits:
- Write
options = {}so callers may leave out the whole settings object. - Use
??so0stays a real setting. - Use
?.before a field that may be missing. - When data should say "empty on purpose", expect
null. The null lesson covers it.
const response = { user: { name: "Asha" } };console.log(response.user?.name ?? "Guest");console.log(response.user?.phone ?? "No phone");The response has a name but no phone. ?. makes the read safe, and ?? turns the undefined into the text "No phone".
Common misconceptions
- "undefined means the variable does not exist." No. A variable that exists can hold
undefined. Reading a name that was never created throws an error. - "A missing property and a missing value in the middle behave the same." No.
obj.missingis safe and givesundefined.obj.missing.xthrows a TypeError. - "Array holes store
undefined." No. A hole is an empty spot with nothing stored. Reading it givesundefined, butindex in arrayisfalse. - "Defaults replace
null." No. Defaults are used only forundefinedand for missing arguments or properties. - "JSON has an
undefinedvalue." No. JSON hasnull, but it has noundefined.
The table below compares four ways a value can be missing. Read each row from left to right: what you have, an example, what reading it gives, whether the key exists, and what JSON gives.
| What you have | Example | What does reading it give? | Does the key exist? | What does JSON.stringify give? |
|---|---|---|---|---|
| A variable with no value | let x; | Reading x gives undefined. typeof x gives "undefined". | x is a variable, not a key, so there is no key to check. | JSON.stringify({ x }) gives {}. |
| A property that is not there | const obj = {}; obj.x | Reading obj.x gives undefined. | No. "x" in obj is false. | JSON.stringify(obj) gives {}. |
A property that holds undefined | { x: undefined } | Reading obj.x gives undefined. | Yes. "x" in obj and Object.hasOwn(obj, "x") are both true. | JSON leaves the key out. |
| A name that was never created | neverDeclared | Reading it throws a ReferenceError. typeof neverDeclared safely gives "undefined". | It is not a key, so in cannot check it. | You cannot turn it into JSON, because you cannot read it. |
Practice exercises
6 EXERCISESPredict the three lines the console prints, in order.
let x;
const obj = {};
console.log(x);
console.log(obj.missing);
console.log([1][1]);All three lines print undefined: a variable with no value, a property the object does not have, and an array index past the end.
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 a default is not used for null.
Predict what the two key checks print.
const settings = { theme: undefined };
console.log("theme" in settings);
console.log("mode" in settings);"theme" in settings is true, because the key is there. "mode" in settings is false, because it is not.
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);?. gives undefined, because there is no address. Then ?? replaces it with Unknown.
Predict the three lines the console prints.
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 check safe, even though maybeName was never created?
if (typeof maybeName === "undefined") {
console.log("safe");
}if (typeof maybeName === "undefined") {
console.log("safe");
}Use typeof. It can look at a name that was never created, and it gives the text "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 a
letvariable with no value print?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 check is safe for a name that might never have been created?
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"give?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 8What does JSON do with
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 a value, and also its own type.typeof undefinedgives"undefined".- You get it when nothing was put into a place, found, passed in, or returned.
- Reading a name that was never created throws a ReferenceError.
typeof neverDeclaredis the safe way to check. - Defaults are used for
undefined, not fornull. - Choose
?.,??,Object.hasOwn, and the JSON rules on purpose. Don't rely onif (value)alone.
Final definition: undefined is JavaScript's built-in value, and type, for a place that exists but has nothing in it.
Up next: null, the value you write yourself when you want to say "nothing here, on purpose."