JavaScript Data Types Overview
JavaScript has two main categories of data types:
- Primitive Types: Basic data types that are immutable (cannot be changed)
- Reference Types: Complex data types like objects, arrays, and functions
Today, we'll focus on the primitive data types, which are the fundamental building blocks of JavaScript.
Analogy: Primitive Types as Atoms
Think of primitive data types as the atoms of programming—they're the simplest, indivisible units that everything else is built from. Just as atoms combine to form molecules with completely different properties (like hydrogen and oxygen forming water), JavaScript primitives combine to create complex data structures with entirely new behaviors and capabilities.
String Type
Strings represent text data in JavaScript. They are sequences of characters enclosed in quotes.
Creating Strings
// Three ways to create a string
const singleQuotes = 'Hello world';
const doubleQuotes = "Hello world";
const backticks = `Hello world`; // Template literals (ES6)
String Properties
const text = "JavaScript";
// Length property
console.log(text.length); // 10
// Accessing characters
console.log(text[0]); // "J"
console.log(text[4]); // "S"
// Strings are immutable - they cannot be changed
text[0] = "j"; // This does nothing
console.log(text); // Still "JavaScript"
Common String Methods
const phrase = "The quick brown fox";
// Converting case
console.log(phrase.toUpperCase()); // "THE QUICK BROWN FOX"
console.log(phrase.toLowerCase()); // "the quick brown fox"
// Finding substrings
console.log(phrase.indexOf("quick")); // 4
console.log(phrase.includes("brown")); // true
console.log(phrase.startsWith("The")); // true
console.log(phrase.endsWith("dog")); // false
// Extracting substrings
console.log(phrase.slice(4, 9)); // "quick"
console.log(phrase.substring(4, 9)); // "quick"
console.log(phrase.split(" ")); // ["The", "quick", "brown", "fox"]
// Trimming whitespace
const paddedText = " spaced out ";
console.log(paddedText.trim()); // "spaced out"
console.log(paddedText.trimStart()); // "spaced out "
console.log(paddedText.trimEnd()); // " spaced out"
// Replacing content
console.log(phrase.replace("fox", "dog")); // "The quick brown dog"
console.log(phrase.replaceAll("o", "0")); // "The quick br0wn f0x"
Template Literals (ES6+)
const name = "Alice";
const age = 28;
// String concatenation (old way)
const greeting1 = "Hello, " + name + "! You are " + age + " years old.";
// Template literals with variable interpolation
const greeting2 = `Hello, ${name}! You are ${age} years old.`;
console.log(greeting1); // "Hello, Alice! You are 28 years old."
console.log(greeting2); // "Hello, Alice! You are 28 years old."
// Multi-line strings
const multiLine = `This is a string
that spans across
multiple lines.`;
console.log(multiLine);
// This is a string
// that spans across
// multiple lines.
// Expression evaluation in template literals
console.log(`2 + 2 = ${2 + 2}`); // "2 + 2 = 4"
console.log(`${name.toUpperCase()} is ${age < 30 ? 'young' : 'mature'}`); // "ALICE is young"
Real-World Example: Form Validation
Strings are frequently used for form validation in web applications:
function validateEmail(email) {
// Remove whitespace
const trimmedEmail = email.trim();
// Check if empty
if (trimmedEmail.length === 0) {
return "Email is required";
}
// Check for @ symbol
if (!trimmedEmail.includes('@')) {
return "Email must contain an @ symbol";
}
// Check for domain
const parts = trimmedEmail.split('@');
if (parts.length !== 2 || parts[1].length === 0) {
return "Email must have a valid domain";
}
// Check domain has at least one dot
if (!parts[1].includes('.')) {
return "Email domain must contain a dot";
}
// Additional check for domain extension
const domainParts = parts[1].split('.');
const extension = domainParts[domainParts.length - 1];
if (extension.length < 2) {
return "Email domain must have a valid extension";
}
return null; // No errors
}
// Test the validation
const emails = [
"user@example.com",
"invalid-email",
"no@domain@test.com",
"missing.extension@test",
" spaces@example.com "
];
emails.forEach(email => {
const error = validateEmail(email);
if (error) {
console.log(`"${email}" is invalid: ${error}`);
} else {
console.log(`"${email}" is valid`);
}
});
Number Type
The Number type represents both integer and floating-point numbers in JavaScript. Unlike some other programming languages, JavaScript doesn't have separate types for integers and floats.
Creating Numbers
// Integer values
const integer = 42;
const negativeNum = -17;
// Floating point (decimal) values
const float = 3.14159;
const negativeFloat = -2.718;
// Scientific notation
const largeNumber = 1.2e6; // 1.2 * 10^6 = 1,200,000
const tinyNumber = 5e-7; // 5 * 10^-7 = 0.0000005
// Binary, octal and hexadecimal notations
const binary = 0b1010; // 10 in decimal
const octal = 0o744; // 484 in decimal
const hex = 0xFF; // 255 in decimal
Special Number Values
// Infinity values
const positiveInfinity = Infinity; // or Number.POSITIVE_INFINITY
const negativeInfinity = -Infinity; // or Number.NEGATIVE_INFINITY
// Not a Number (NaN)
const notANumber = NaN; // or Number.NaN
// Checking for NaN
console.log(isNaN(NaN)); // true
console.log(isNaN("hello")); // true (string isn't a number)
console.log(isNaN(42)); // false
// More precise check
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("hello")); // false (specifically checks for NaN value)
Number Range and Precision
// Smallest and largest safe integers
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
// Smallest and largest values
console.log(Number.MIN_VALUE); // 5e-324 (closest to zero)
console.log(Number.MAX_VALUE); // 1.7976931348623157e+308
// Precision issues with floating point
console.log(0.1 + 0.2); // 0.30000000000000004, not exactly 0.3
console.log(0.1 + 0.2 === 0.3); // false
// Handling precision issues
console.log(Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON); // true
console.log(Number((0.1 + 0.2).toFixed(1)) === 0.3); // true
Number Methods
const num = 42.3567;
// Conversion methods
console.log(num.toString()); // "42.3567"
console.log(num.toFixed(2)); // "42.36" (string with 2 decimal places)
console.log(num.toPrecision(3)); // "42.4" (string with 3 significant digits)
console.log(num.toExponential()); // "4.23567e+1" (exponential notation)
// Parsing strings to numbers
console.log(parseInt("42")); // 42
console.log(parseInt("42.95")); // 42 (truncates decimal part)
console.log(parseInt("42px")); // 42 (stops at non-numeric character)
console.log(parseInt("0xFF", 16)); // 255 (parses hex with radix 16)
console.log(parseFloat("42.95")); // 42.95
console.log(parseFloat("42")); // 42
console.log(parseFloat("42.0px")); // 42 (stops at non-numeric character)
// Number constructor
console.log(Number("42")); // 42
console.log(Number("42.5")); // 42.5
console.log(Number(" 42 ")); // 42 (trims whitespace)
console.log(Number("42px")); // NaN (doesn't parse partial numbers)
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
The Math Object
// Mathematical constants
console.log(Math.PI); // 3.141592653589793
console.log(Math.E); // 2.718281828459045
// Rounding methods
console.log(Math.round(4.7)); // 5
console.log(Math.round(4.4)); // 4
console.log(Math.floor(4.9)); // 4 (rounds down)
console.log(Math.ceil(4.1)); // 5 (rounds up)
console.log(Math.trunc(4.9)); // 4 (removes decimal part)
// Min, max and absolute
console.log(Math.min(5, 10, 3, 8)); // 3
console.log(Math.max(5, 10, 3, 8)); // 10
console.log(Math.abs(-42)); // 42
// Power and square root
console.log(Math.pow(2, 3)); // 8 (2^3)
console.log(Math.sqrt(16)); // 4
console.log(Math.cbrt(27)); // 3 (cube root)
// Random numbers
console.log(Math.random()); // Random number between 0 (inclusive) and 1 (exclusive)
// Generate random integer between min and max (inclusive)
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomInt(1, 6)); // Random dice roll (1-6)
Analogy: Floating-Point Precision
JavaScript's floating-point precision issues are like trying to represent 1/3 in decimal form: you can get close (0.333333...), but you can never represent it exactly with a finite number of digits. Similarly, many decimal fractions (like 0.1 and 0.2) can't be represented exactly in binary floating-point format, leading to tiny rounding errors that become visible when you perform calculations.
Real-World Example: Shopping Cart Total
When building an e-commerce application, you need to handle monetary calculations carefully:
function calculateCartTotal(items) {
// Calculate subtotal
let subtotal = 0;
items.forEach(item => {
// Price in dollars, e.g. 10.99
const itemTotal = item.price * item.quantity;
subtotal += itemTotal;
});
// Fix precision issues by converting to cents for calculations
const subtotalCents = Math.round(subtotal * 100);
// Calculate tax (for example, 8.25%)
const taxRate = 0.0825;
const taxCents = Math.round(subtotalCents * taxRate);
// Calculate total
const totalCents = subtotalCents + taxCents;
// Convert back to dollars for display
return {
subtotal: (subtotalCents / 100).toFixed(2),
tax: (taxCents / 100).toFixed(2),
total: (totalCents / 100).toFixed(2)
};
}
// Test with a sample cart
const cart = [
{ name: 'Widget', price: 9.99, quantity: 2 },
{ name: 'Gadget', price: 12.50, quantity: 1 },
{ name: 'Doohickey', price: 5.95, quantity: 3 }
];
console.log(calculateCartTotal(cart));
Boolean Type
The Boolean type has only two possible values: true and false. Booleans are used for conditional logic and represent the concept of truth and falsehood in JavaScript.
Creating Booleans
// Boolean literals
const isActive = true;
const isComplete = false;
// From comparison operations
const isGreater = 5 > 3; // true
const isEqual = 10 === '10'; // false
// Using the Boolean constructor
const boolTrue = Boolean(1); // true
const boolFalse = Boolean(0); // false
Truthy and Falsy Values
In JavaScript, all values have an inherent Boolean value when used in a Boolean context, known as "truthy" or "falsy."
Falsy values (convert to false):
// All of these are falsy:
console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean(-0)); // false
console.log(Boolean(0n)); // false (BigInt zero)
console.log(Boolean("")); // false (empty string)
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
Truthy values (convert to true):
// All other values are truthy, including:
console.log(Boolean(true)); // true
console.log(Boolean(42)); // true (any non-zero number)
console.log(Boolean("false")); // true (non-empty string, even "false")
console.log(Boolean({})); // true (empty object)
console.log(Boolean([])); // true (empty array)
console.log(Boolean(function(){})); // true (functions)
Logical Operators
// Logical AND (&&) - returns first falsy value or last truthy value
console.log(true && false); // false
console.log(false && anyExpression); // false (short-circuits, doesnt evaluate second expression)
console.log("Hello" && 42 && true); // true (last value)
console.log("Hello" && 0 && true); // 0 (first falsy value)
// Logical OR (||) - returns first truthy value or last falsy value
console.log(true || false); // true
console.log(true || anyExpression); // true (short-circuits)
console.log(false || "" || null); // null (last value)
console.log(false || 0 || "Hello"); // "Hello" (first truthy value)
// Logical NOT (!) - inverts truthiness
console.log(!true); // false
console.log(!false); // true
console.log(!"Hello"); // false (string is truthy)
console.log(!""); // true (empty string is falsy)
// Double NOT (!!) - converts to Boolean
console.log(!!"Hello"); // true
console.log(!!0); // false
Nullish Coalescing Operator (??)
ES2020 introduced the nullish coalescing operator, which is similar to OR but only treats null and undefined as falsy.
// The ?? operator only considers null and undefined as falsy
const value1 = 0 ?? "default"; // 0 (0 is a valid value)
const value2 = "" ?? "default"; // "" (empty string is a valid value)
const value3 = null ?? "default"; // "default"
const value4 = undefined ?? "default"; // "default"
// Compare with OR
const withOr1 = 0 || "default"; // "default" (0 is falsy)
const withOr2 = "" || "default"; // "default" (empty string is falsy)
Analogy: Truthy and Falsy as Light Switches
Think of JavaScript's truthiness as light switches. Some values are like switches that are definitely "off" (falsy values like false, 0, "", null, undefined, and NaN), and all other values are like switches that are definitely "on" (truthy). When JavaScript needs to make a decision based on a condition, it checks whether the switch is on or off, regardless of what type of value it is.
Real-World Example: Form Validation with Conditional Logic
Boolean logic is essential for form validation:
function validateUserInput(username, email, password) {
const errors = {};
// Username validation
if (!username) {
errors.username = "Username is required";
} else if (username.length < 3) {
errors.username = "Username must be at least 3 characters";
}
// Email validation
if (!email) {
errors.email = "Email is required";
} else if (!email.includes('@') || !email.includes('.')) {
errors.email = "Email format is invalid";
}
// Password validation
if (!password) {
errors.password = "Password is required";
} else {
const hasMinLength = password.length >= 8;
const hasUppercase = /[A-Z]/.test(password);
const hasLowercase = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
if (!(hasMinLength && hasUppercase && hasLowercase && hasNumber)) {
errors.password = "Password must be at least 8 characters with uppercase, lowercase, and numbers";
}
}
// Return validation result
return {
isValid: Object.keys(errors).length === 0,
errors: errors
};
}
// Test the validation
const result = validateUserInput("joe", "invalid-email", "password123");
console.log(result.isValid); // false
console.log(result.errors); // Object with validation errors
Undefined Type
The undefined type has only one value: undefined. It represents a variable that has been declared but not assigned a value.
When Undefined Occurs
// Variable declared but not initialized
let uninitializedVar;
console.log(uninitializedVar); // undefined
// Missing function parameters
function greet(name) {
console.log(`Hello, ${name}`);
}
greet(); // "Hello, undefined"
// Missing object properties
const user = { name: "Alice" };
console.log(user.age); // undefined
// Function with no return statement
function noReturn() {
// No return statement
}
console.log(noReturn()); // undefined
Checking for Undefined
// Using strict equality
function processValue(value) {
if (value === undefined) {
return "No value provided";
}
return `Processing: ${value}`;
}
// Using typeof
function safelyProcessValue(value) {
if (typeof value === "undefined") {
return "No value provided";
}
return `Processing: ${value}`;
}
// Avoid this pattern (global undefined can be overwritten in older browsers)
function badCheck(value) {
if (value == undefined) { // uses loose equality, also matches null
return "No value provided";
}
return `Processing: ${value}`;
}
Optional Chaining (?.) for Undefined
ES2020 introduced optional chaining to safely access nested properties that might be undefined.
// Object with nested properties
const user = {
name: "Alice",
address: {
city: "Wonderland"
}
};
// Old way (error-prone)
let zipCode;
if (user && user.address && user.address.zipCode) {
zipCode = user.address.zipCode;
} else {
zipCode = "Unknown";
}
// With optional chaining
const zipCode2 = user?.address?.zipCode ?? "Unknown";
// Also works with function calls
const result = user.getDetails?.() ?? "Method not available";
Analogy: Undefined as an Empty Slot
Think of undefined as an empty slot in a mailbox. The slot exists (