FullStack Course LogoFullStack Course
Module: JavaScript
JavaScript·044·9 MIN READ

044: Values and Data Types

TOPICS COVERED: Values and Data Types

Outcomes

By the end of this lesson, you can:

  • recognize string, number, Boolean, undefined, null, object, and array values;
  • explain the difference between primitive and object values at a beginner level;
  • inspect values with typeof and identify its important exceptions;
  • choose a suitable type for realistic data; and
  • avoid confusing a value's type with the variable that currently holds it.

Prerequisites and Retrieval

Before starting, retrieve the roles of const, let, initialization, reassignment, and block scope from lesson 043.

  1. Which declaration should be your default?
  2. Which declaration allows a new assignment?
  3. Is "42" visibly the same kind of literal as 42?

Use a fresh browser console or a module script. Predict each type before you run the examples; that small pause makes the later output much easier to interpret.

Terms

  • data type: The classification of values: seven primitives plus Object. — Source: MDN: Data structures
  • primitive: “Data that is not an object and has no methods”: string, number, bigint, boolean, undefined, symbol, null. — Source: MDN: Primitive
  • string: An immutable sequence of characters representing text. — Source: MDN: String
  • number: Double-precision 64-bit IEEE value including integers and NaN/Infinity. — Source: MDN: Number
  • Boolean: Logical type with exactly two values: true and false. — Source: MDN: Boolean
  • undefined: Value of a declared-but-uninitialized variable; also missing property access result. — Source: MDN: undefined
  • null: A deliberate “no value” marker; typeof null returns "object" historically. — Source: MDN: null
  • object: A collection of properties keyed by strings/symbols; arrays and functions are objects. — Source: MDN: Object
  • array: An ordered list-like object with numeric indices starting at 0. — Source: MDN: Array
  • dynamic typing: Types attach to values, so one variable can hold different types over time. — Source: MDN: Data structures
  • typeof: Operator returning a string describing a value’s type. — Source: MDN: typeof
  • Primitive (official): "A primitive is data that is not an object and has no methods; there are 7 primitives: string, number, bigint, boolean, undefined, symbol, null." — Source: MDN: Primitive
  • Reference: "A reference is a pointer to an object in memory; copying a reference copies the pointer, not the object." — Source: MDN: Data structures — Objects

Beginner Explanation and Mental Model

Programs represent facts with values. Choosing a type is similar to choosing the right field on a form: a name belongs in a text field, a price is numeric, and an enrollment state is Boolean. The type affects what an operation means. 10 + 5 calculates 15, while "10" + "5" joins two pieces of text and produces "105".

JavaScript defines seven primitive types: string, number, Boolean, undefined, null, BigInt, and Symbol. This lesson concentrates on the first five in that list because they provide the core beginner model. BigInt and Symbol solve more specialized problems and are covered later in this lesson as extensions. Values that are not primitive are objects. Arrays look and behave like lists, but technically an array is an object too.

js
const userName = "Leela";   // string
const score = 88.5;             // number
const passed = true;            // boolean
let feedback;                   // undefined
const selectedContact = null;    // null
const user = { name: "Leela" }; // object
const skills = ["HTML", "CSS"];   // array object

In everyday code, undefined commonly means that something was not supplied or has not been initialized. null is usually assigned intentionally to record known absence. They are distinct values, so null === undefined is false. Do not use the strings "null" or "undefined" to represent absence; those are ordinary text and will behave like any other strings.

For the current mental model, treat primitive values as individual values. Objects group related data and are accessed through references. If two variables refer to the same object, a mutation made through either reference is visible through the other. The later object lessons will examine that behavior in more detail.

Inspecting types

The typeof operator returns a string describing the value it receives:

js
console.log(typeof "hello"); // string
console.log(typeof 12);      // number
console.log(typeof false);   // boolean
console.log(typeof undefined); // undefined

There are two important exceptions to keep in your mental checklist. They are historical or structural behavior, not bugs you can correct in your code:

js
console.log(typeof null);     // object (historical behavior)
console.log(typeof [1, 2]);   // object
console.log(Array.isArray([1, 2])); // true

Use value === null when the question is specifically whether a value is null. Use Array.isArray(value) when you need to identify an array. typeof remains useful, but it is not a complete value classifier.

JavaScript is dynamically typed. Types belong to values rather than being permanently attached to a binding, so the same variable can hold values of different types over time:

js
let result = 10;
result = "complete";

This is valid JavaScript. In application code, however, changing what a variable means as well as changing its type usually makes the code harder to read and debug. Give each variable one stable meaning when you can.

Worked Example: User Profile Values

Run this complete example and compare each printed value with the type you predicted:

js
const userName = "Nila";
const userAge = 20;
const isEnrolled = true;
let latestScore;
const contact = null;
const profile = { city: "Chennai" };
const subjects = ["HTML", "CSS", "JavaScript"];

console.log(userName, typeof userName);
console.log(userAge, typeof userAge);
console.log(isEnrolled, typeof isEnrolled);
console.log(latestScore, typeof latestScore);
console.log(contact, typeof contact);
console.log(profile, typeof profile);
console.log(subjects, typeof subjects);
console.log("Is subjects an array?", Array.isArray(subjects));
console.log("Is contact null?", contact === null);

Expected output (object formatting varies by browser):

text
Nila string
20 number
true boolean
undefined undefined
null object
{city: "Chennai"} object
["HTML", "CSS", "JavaScript"] object
Is subjects an array? true
Is contact null? true

The operator's result is itself text: typeof userAge produces the string "number". It does not change userAge. Because latestScore was declared without an initializer, its value is undefined; let is not the reason for that value by itself. contact, on the other hand, was initialized deliberately to null. Both profile and subjects report "object", so the dedicated array check is what separates the array case.

Intermediate Example: Validate a Data Shape

For this example, use only simple Boolean checks. Branching comes in lesson 047 after coercion and operators, so the goal here is to read and interpret the type results:

js
const product = {
  name: "Keyboard",
  price: 1500,
  inStock: true,
  discount: null,
};

const tags = ["accessory", "input"];

const hasValidName = typeof product.name === "string";
const hasValidPrice = typeof product.price === "number";
const hasStockFlag = typeof product.inStock === "boolean";
const hasNoDiscount = product.discount === null;
const hasTagList = Array.isArray(tags);

console.log("Name valid:", hasValidName);
console.log("Price valid:", hasValidPrice);
console.log("Stock flag valid:", hasStockFlag);
console.log("No discount:", hasNoDiscount);
console.log("Tags valid:", hasTagList);

The expected output is five lines ending in true. These checks establish types and one explicit absence marker; they do not prove that the data is valid for every business rule. -500 still has type number, and an empty string still has type string. Real validation adds range, emptiness, and domain checks later.

One numeric edge case is worth adding now: NaN also has type "number". It represents an invalid numeric result, not a usable number. When you need to distinguish it, use Number.isNaN(value). Do not write value === NaN; that comparison is always false.

Optional Advanced Extension: Primitive Copy vs Shared Reference

js
let firstScore = 80;
let copiedScore = firstScore;
copiedScore = 95;

const firstList = ["HTML"];
const sharedList = firstList;
sharedList.push("CSS");

console.log(firstScore, copiedScore);
console.log(firstList);
console.log(firstList === sharedList);

Expected output:

text
80 95
["HTML", "CSS"]
true

In this practical model, assigning a primitive copies its value. Assigning an object copies a reference, so both bindings identify the same array. This is enough reference behavior for this lesson; deep and shallow copying belong to a later discussion.

Interview focus: values, references, and ownership

JavaScript is pass-by-value. With a primitive, the value passed to a function is the primitive itself. With an object, the value passed to the function is a copy of the reference to that object. That is why the short answer “objects are passed by reference” is misleading: the parameter receives its own value, but that value points to the same object.

js
function change(score, user) {
  score = 100;
  user.name = "Mina";
  user = { name: "Replacement" };
}

const score = 60;
const user = { name: "Ravi" };
change(score, user);

console.log(score);       // 60: the parameter was reassigned
console.log(user.name);   // Mina: both references reached the same object

A common follow-up question is how to prevent a function from changing the caller's object. Return a new object, or make an explicit copy at the boundary. Do not claim that const solves the problem: const prevents reassignment of a binding, not mutation of the object that binding names.

js
function rename(user, name) {
  return { ...user, name };
}

const nextUser = rename(user, "Leela");
console.log(nextUser === user); // false

This distinction explains both sides of the behavior. Reassigning a parameter's reference does not replace the caller's variable, while changing a property through that reference can be visible to the caller.

Deep Dive: Primitives, Identity, BigInt, and Symbol

Primitive values are immutable values. Objects have identity and are handled through references. The difference becomes clear when you compare assignment of a string with assignment of an object.

js
let first = "tea";
let second = first;
second = "coffee";

console.log(first); // "tea"

Compare that with an object:

js
const firstOrder = { total: 120 };
const secondOrder = firstOrder;

secondOrder.total = 150;

console.log(firstOrder.total); // 150

Both variables identify the same object, so changing its total property is observable through either variable.

BigInt

The number type is an IEEE-754 floating-point value. Once integers grow beyond the safe integer range, a number may no longer represent every integer exactly.

js
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991

const ledgerId = 9007199254740993n;
console.log(ledgerId + 1n);

Do not mix number and bigint in arithmetic without an explicit conversion.

js
// 10n + 5 // TypeError
Number(10n) + 5;

Symbol

Symbols are unique primitive values. They are useful for property keys that should not collide with ordinary string keys and for certain language protocols.

js
const internalId = Symbol("internalId");

const order = {
  number: "ORD-1001",
  [internalId]: 8472,
};

console.log(order.number);
console.log(order[internalId]);

Symbol.iterator becomes especially important later because it defines how an object participates in for...of iteration.

typeof edge cases worth remembering

js
typeof null;           // "object" — historical quirk
typeof [];             // "object"
Array.isArray([]);     // true
typeof function () {}; // "function"
typeof 1n;             // "bigint"
typeof Symbol();       // "symbol"

Choose the inspection tool for the question you are asking. typeof can identify broad categories, value === null detects deliberate null, and Array.isArray() detects arrays.

Mistakes and Debugging

  • Forgetting quotes: const city = Chennai; looks for a variable named Chennai. Use "Chennai" for text.
  • Quoting numbers: a price of "500" is text and may concatenate. Store numeric facts as 500.
  • Quoting Booleans: "false" is a non-empty string, not the Boolean false.
  • Assuming typeof null is "null": test with value === null.
  • Assuming arrays have typeof result "array": use Array.isArray().
  • Treating undefined and undeclared as identical: an initialized/declared variable may contain undefined; reading a completely undeclared name throws ReferenceError.
  • Using typeof as full validation: combine it later with ranges, emptiness checks, and domain rules.
  • Relying on coercion: convert inputs explicitly at system boundaries instead of hoping operators infer intent.

When debugging a surprising value, log the value and its type together: console.log("price", price, typeof price);. Then trace backward to the earliest point where the actual type differs from the expected type. That boundary often reveals whether the problem entered through form input, parsing, reassignment, or another system boundary.

Best Practices

  • Model text as strings, quantities as numbers, states as Booleans, intentional absence as null, and ordered collections as arrays.
  • Use lowercase true, false, null, and undefined.
  • Prefer null only when the application deliberately records absence; do not sprinkle it as a universal default.
  • Do not explicitly assign undefined unless an API contract requires it.
  • Use Array.isArray() for arrays and strict equality for null.
  • Keep each variable's meaning and expected type stable.
  • Avoid wrapper objects such as new Boolean(false) and new String("text"); use primitives.
  • Treat browser form input as strings until explicitly validated and converted.

Tiered Exercises

Core

Create one value of each required type: string, number, Boolean, undefined, null, object, and array. Log each value and its typeof result. Use Array.isArray() for the list.

Practice

Model a book using a title, page count, availability flag, optional borrower, a small details object, and an array of genres. Choose appropriate types and print checks that demonstrate those choices.

Professional Extension

Predict the results of typeof null, typeof [], Array.isArray({}), Array.isArray([]), typeof NaN, and null === undefined. Then verify each result and explain why it occurs.

Complete Solutions

js
const textValue = "JavaScript";
const numberValue = 31;
const booleanValue = true;
let undefinedValue;
const nullValue = null;
const objectValue = { topic: "types" };
const arrayValue = [31, 32, 33];

console.log(textValue, typeof textValue);
console.log(numberValue, typeof numberValue);
console.log(booleanValue, typeof booleanValue);
console.log(undefinedValue, typeof undefinedValue);
console.log(nullValue, typeof nullValue);
console.log(objectValue, typeof objectValue);
console.log(arrayValue, typeof arrayValue, Array.isArray(arrayValue));
js
const title = "Clean Code Basics";
const pageCount = 240;
const isAvailable = true;
const borrower = null;
const details = { language: "English" };
const genres = ["technology", "education"];

console.log(typeof title === "string");
console.log(typeof pageCount === "number");
console.log(typeof isAvailable === "boolean");
console.log(borrower === null);
console.log(typeof details === "object" && details !== null);
console.log(Array.isArray(genres));

Every line prints true.

js
console.log(typeof null);       // object: historical exception
console.log(typeof []);         // object: arrays are objects
console.log(Array.isArray({})); // false
console.log(Array.isArray([])); // true
console.log(typeof NaN);        // number
console.log(null === undefined); // false: different primitive values

Recap and Exit Questions

Types describe values and influence how operations behave. Strings, numbers, Booleans, undefined, and null are primitives. Objects group data, and arrays are specialized objects. typeof is useful as long as you account for its null and array exceptions.

  1. Why should a price usually be a number rather than a numeric string?
  2. How do undefined and null differ in intent?
  3. What does typeof return, and what type is that return value?
  4. How should code detect an array?
  5. What does dynamic typing mean?

Official References

References checked 2026-08-24.

Reader page: /javascript/lesson/044/values-and-data-types