SECTION 1
Historical Context & Motivation
Every programming language needs a way to represent different kinds of data—numbers for math, text for messages, true/false values for decisions. When Brendan Eich created JavaScript in just ten days in 1995, he designed a small but powerful set of data types that would let web pages come alive with interactivity. Unlike languages such as Java or C++, JavaScript was designed to be dynamically typed, meaning a variable could hold a number one moment and a string the next. This flexibility made JavaScript approachable for beginners, but it also meant that understanding types became even more important for avoiding tricky bugs.
1995 • JavaScript Is Born
1997 • ECMAScript 1 Standard
number, string, boolean, null, undefined, and object as the core types of the language.2009 • ES5 & Strict Mode
2015 • ES6 Adds Symbol & let/const
Symbol as a new primitive type, along with let and const for better variable declarations. The original six types remain foundational.2020 • BigInt Arrives
BigInt for arbitrarily large integers. Despite newer additions, the original six types still form the backbone of virtually all JavaScript code.So here's the central question this lesson tackles: what exactly are JavaScript's six original data types, how do they differ from one another, and why does choosing the right type matter when you're writing code? Let's find out.
SECTION 2
Core Principles & Definitions
A data type tells JavaScript what kind of value a variable holds and what operations you can perform on it. JavaScript divides its types into two major categories: primitive types and reference types. Primitives are simple, immutable values—once created, they cannot be changed in place. The reference type (object) is a container that can hold collections of data and more complex entities.
Primitive vs. Reference
number, string, boolean, null, undefined) store a single, immutable value directly. Objects store a reference (address) pointing to data in memory.Dynamic Typing
let x = 5 is automatically a number.The typeof Operator
typeof to check what type a value is at any time. For example, typeof 42 returns "number".Type Coercion
"5" + 3 produces "53" (a string), not 8. Understanding types helps you predict and prevent these surprises.Immutability of Primitives
KEY TAKEAWAY
SECTION 3
Visual Overview of JavaScript Types
The diagram above divides JavaScript's type system into two halves. On the left, inside the dashed border, you see the five primitive types. Each one stores a simple, self-contained value—like a sticky note with one fact written on it. On the right sits the object type, which acts as a container that can hold many values organized by keys. Notice the key distinction at the bottom: primitives are immutable and stored by value, while objects are mutable and stored by reference. This difference has major consequences for how your code behaves when you copy or compare data.
SECTION 4
How Each Type Works Under the Hood
Number
JavaScript uses a single number type for both integers and decimals. Internally, every number is a 64-bit floating-point value following the IEEE 754 standard. This means 5 and 5.0 are actually the same value. Numbers also include three special values: Infinity (result of dividing by zero), -Infinity, and NaN ("Not a Number"), which appears when a math operation doesn't make sense, like "hello" * 2.
String
A string is a sequence of characters enclosed in single quotes ('hello'), double quotes ("hello"), or backticks (`hello`). Backtick strings, called template literals, let you embed expressions directly using ${expression} syntax. Strings are immutable—when you call a method like .toUpperCase(), it returns a new string rather than modifying the original.
Boolean
A boolean has exactly two possible values: true or false. Booleans are the backbone of conditional logic. Every if statement, while loop, and logical operator ultimately evaluates to a boolean. JavaScript also treats certain values as "falsy" (they behave like false in conditions): 0, "", null, undefined, and NaN. Everything else is "truthy".
Null and Undefined
Both null and undefined represent "no value," but they serve different purposes. undefined is what JavaScript assigns automatically when a variable has been declared but not yet given a value. null is an intentional assignment—a programmer's way of saying "this value is deliberately empty." Think of undefined as an empty parking spot that nobody planned, while null is a reserved parking spot with a sign that reads "kept empty on purpose."
Object
An object is a collection of key-value pairs. Keys are always strings (or Symbols), and values can be any type—including other objects. Arrays ([1, 2, 3]), functions, dates, and regular expressions are all specialized objects. Unlike primitives, objects are mutable: you can add, change, or delete properties after creation. When you assign an object to a new variable, both variables point to the same data in memory, which means changes through one variable are visible through the other.
Watch Out: typeof null
typeof null returns "object" instead of "null". This quirk has been kept for backward compatibility. When checking for null, always use strict equality: value === null.SECTION 5
Type Classification & the typeof Operator
The typeof operator is your primary tool for inspecting types at runtime. It returns a string describing the type of its operand. The table below shows every input-output combination you need to know, including the notorious null quirk.
| Expression | typeof Result | Actual Type |
|---|---|---|
typeof 42 | "number" | number |
typeof 3.14 | "number" | number |
typeof NaN | "number" | number (special) |
typeof "hello" | "string" | string |
typeof true | "boolean" | boolean |
typeof undefined | "undefined" | undefined |
typeof null | "object" | null (bug!) |
typeof { a: 1 } | "object" | object |
typeof [1, 2] | "object" | object (array) |
typeof function(){} | "function" | object (function) |
typeof results for common JavaScript values
typeof categorizes values into its possible return strings. Note the two gotchas at the bottom: NaN is classified as a number, and null is reported as "object."The flowchart above traces the path of a value through typeof. When you need to distinguish between an actual object and null, or between a plain object and an array, typeof alone won't cut it. Use value === null for null checks and Array.isArray(value) for array checks.
SECTION 6
Worked Example — Identifying and Using Types
Let's walk through a realistic scenario. Imagine you're building a simple student profile system. You need to store a student's name, age, enrollment status, GPA, and a list of courses. Along the way, we'll identify the type of each piece of data and see how typeof confirms our choices.
Building a Student Profile with Correct Types
- 1
Step 1 — Declare variables with appropriate types
We create variables for each piece of student data. The name is a string, the age is a number, the enrollment flag is a boolean, and the GPA starts as null because it hasn't been calculated yet.let name = "Aisha"; let age = 16; let enrolled = true; let gpa = null; - 2
Step 2 — Check types with typeof
We verify each variable's type usingtypeof. Notice thattypeof gpareturns"object"(the historic bug), so we usegpa === nullfor a reliable check instead.typeof name → "string", typeof age → "number", typeof enrolled → "boolean", typeof gpa → "object", gpa === null → true - 3
Step 3 — Create an object to group the data
Rather than keeping five separate variables, we combine them into an object. The object uses descriptive keys, and its values span multiple types.let student = { name: "Aisha", age: 16, enrolled: true, gpa: null, courses: ["Math", "CS", "English"] }; - 4
Step 4 — Access properties and observe type behavior
We readstudent.age(a number) andstudent.courses(an array, which is a type of object). We can confirm the array withArray.isArray(student.courses), which returnstrue.student.age → 16 (number), Array.isArray(student.courses) → true - 5
Step 5 — Update a value and notice mutability
We assign a GPA now that grades are in:student.gpa = 3.8;. The object is mutable, so this change happens in place. If we had copied the object to another variable, that variable would also reflect the change because objects are stored by reference.student.gpa → 3.8, typeof student.gpa → "number"
SECTION 7
Comparing the Six Types — Strengths & Pitfalls
Each type has its natural strengths and a few common pitfalls that trip up beginners. The table below summarizes the key characteristics so you can make confident decisions about which type to use for any piece of data.
| Type | Best Used For | Common Pitfall |
|---|---|---|
number | Counts, measurements, math operations, coordinates | Floating-point precision: 0.1 + 0.2 !== 0.3 due to rounding |
string | Names, messages, IDs, any textual data | Concatenation surprise: "5" + 3 yields "53" not 8 |
boolean | Flags, toggles, conditions, filter logic | Confusing truthy/falsy values—"0" (string) is truthy, but 0 (number) is falsy |
null | Intentional "no value" placeholder | typeof null returns "object"—always use === null |
undefined | Detecting uninitialized variables or missing properties | Accidentally accessing a misspelled property returns undefined without an error |
object | Grouping related data, arrays, complex structures | Reference sharing: two variables can point to the same object, causing unintended mutations |
Strengths and pitfalls of JavaScript's six core types
KEY TAKEAWAY
number instead of a string, you'll lose leading zeros (like 0551234567 becoming 551234567). Always think about what operations you need to perform on the data—that usually tells you which type fits best.SECTION 8
Connection to Advanced Type Concepts
The six types you've learned form the foundation, but modern JavaScript and its ecosystem build significantly on top of them. Understanding where these basics lead will prepare you for more powerful tools as your programming skills grow.
| What You Know Now | Where It Leads |
|---|---|
Six core types checked with typeof | TypeScript — a superset of JavaScript that adds static type annotations so errors are caught before your code even runs |
| Dynamic typing (variables can change type) | Type guards — conditional checks (using typeof, instanceof, or custom functions) that narrow a value's type within a code block |
| Objects with key-value pairs | Classes & Prototypes — object blueprints that let you create many objects with the same structure and shared methods |
| Primitive types (number, string, boolean) | Symbol & BigInt — two newer primitive types: Symbol for unique identifiers, BigInt for integers larger than 2⁵³ − 1 |
| Type coercion surprises | Strict equality (===) and linting tools like ESLint that enforce type-safe patterns and prevent coercion bugs in large codebases |
From foundations to advanced type concepts
As you advance, you'll encounter TypeScript in many professional projects. TypeScript doesn't replace what you've learned—it builds directly on top of it. Every TypeScript type annotation maps back to the JavaScript types we've covered. Mastering these six types now gives you a rock-solid foundation for everything that follows.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
null and undefined in JavaScript. Give a real-world analogy for each.Show answer
undefined means a variable exists but has never been assigned a value—like an empty mailbox that hasn't received any mail yet. null means a variable has been deliberately set to "no value"—like a mailbox with a note inside that says "intentionally left empty." JavaScript assigns undefined automatically when you declare a variable without initializing it (let x;), while null must be explicitly assigned by the programmer (let x = null;). Both are falsy values, meaning they evaluate to false in boolean contexts.Question 2: BASIC CALCULATION
typeof expression: (a) typeof 7.5 (b) typeof "true" (c) typeof false (d) typeof null (e) typeof [1, 2, 3]Show answer
"number" — all numeric values, whether integers or decimals, are type number. (b) "string" — the quotes make this a string, not a boolean, even though the text says "true". (c) "boolean" — false without quotes is a boolean literal. (d) "object" — this is the famous typeof bug; null is actually a primitive, but typeof reports it as "object". (e) "object" — arrays are a special kind of object in JavaScript; use Array.isArray() to distinguish arrays from plain objects.Question 3: INTERMEDIATE
let a = "10"; let b = 5; console.log(a + b); console.log(a - b);Show answer
console.log outputs "105" (a string). Because a is a string and the + operator is used, JavaScript performs string concatenation rather than addition. The number 5 gets coerced to the string "5" and is appended to "10". The second console.log outputs 5 (a number). The - operator only works with numbers, so JavaScript coerces the string "10" to the number 10, then computes 10 − 5 = 5. This asymmetry between + and - is a classic source of type coercion bugs.Question 4: APPLIED
describeValue(val) that returns a string describing the type of its argument. It should handle all six types correctly, including the null bug and arrays. Write the function body using typeof, === null, and Array.isArray().Show answer
function describeValue(val) { if (val === null) return "null"; if (Array.isArray(val)) return "array"; return typeof val; }
The key insight is that you must check for null before using typeof, because typeof null would incorrectly return "object". Similarly, checking Array.isArray() before falling through to typeof lets you distinguish arrays from plain objects. For inputs like describeValue(42) → "number", describeValue(null) → "null", describeValue([1,2]) → "array".Question 5: CRITICAL THINKING
let obj1 = { score: 100 }; let obj2 = obj1; obj2.score = 200; console.log(obj1.score);
What does this output and why? Now consider the same pattern with a primitive:
let x = 100; let y = x; y = 200; console.log(x);
What does this output? Explain the fundamental type system concept that causes the different behavior.Show answer
200. When you write let obj2 = obj1, you are not copying the object—you are copying the reference (memory address) that points to the same object. So obj1 and obj2 both point to the exact same object in memory. Changing obj2.score also changes obj1.score because they're the same object. The second snippet outputs 100. Primitives are stored by value, so let y = x creates an independent copy of the number 100. Changing y has no effect on x. This illustrates the fundamental distinction between pass-by-value (primitives) and pass-by-reference (objects) in JavaScript's type system.SUMMARY
Summary — JavaScript Types at a Glance
Summary
JavaScript organizes all data into primitive types and reference types. The five primitives are number (integers, decimals, NaN, Infinity), string (text in quotes or backticks), boolean (true or false), null (intentional empty value), and undefined (not yet assigned). All primitives are immutable and stored by value.
The object type is a mutable collection of key-value pairs that is stored by reference. Arrays, functions, and dates are all objects. Use typeof to check types at runtime, but remember its two quirks: typeof null returns "object" and arrays also report as "object." Guard against these with === null and Array.isArray(). Master these six types and you'll have a solid foundation for every JavaScript program you write.