README
2.2 Data Types
š Table of Contents
- ā¢Overview of Data Types
- ā¢Number
- ā¢String
- ā¢Boolean
- ā¢Null
- ā¢Undefined
- ā¢Symbol
- ā¢BigInt
- ā¢Object (Reference Type)
- ā¢Type Checking
Overview of Data Types
JavaScript has 8 data types, divided into two categories:
Primitive Types (7 types)
Primitives are immutable and stored by value:
| Type | Example | typeof Result |
|---|---|---|
| Number | 42, 3.14, NaN | "number" |
| String | "hello", 'world' | "string" |
| Boolean | true, false | "boolean" |
| Null | null | "object" (bug!) |
| Undefined | undefined | "undefined" |
| Symbol | Symbol("id") | "symbol" |
| BigInt | 9007199254740991n | "bigint" |
Reference Type (1 type)
Objects are mutable and stored by reference:
| Type | Example | typeof Result |
|---|---|---|
| Object | {}, [], function(){} | "object" or "function" |
Primitive vs Reference:
// PRIMITIVE - copied by value
let a = 10;
let b = a; // b gets a COPY of the value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20
// REFERENCE - copied by reference
let obj1 = { name: 'John' };
let obj2 = obj1; // obj2 points to SAME object
obj2.name = 'Jane';
console.log(obj1.name); // "Jane" (changed!)
console.log(obj2.name); // "Jane"
Visual Representation:
PRIMITIVES (stored by value):
āāāāāāāāāāā āāāāāāāāāāā
ā a: 10 ā ā b: 20 ā ā Separate copies
āāāāāāāāāāā āāāāāāāāāāā
OBJECTS (stored by reference):
āāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
ā obj1: āāāā¼āāāāāŗā { name: "Jane" } ā
āāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāā ā²
ā obj2: āāāā¼āāāāāāāāāāāāā ā Both point to same object
āāāāāāāāāāāā
Number
JavaScript has a single number type for both integers and floating-point numbers, using 64-bit floating-point format (IEEE 754).
Creating Numbers:
// Integer
let count = 42;
let negative = -17;
// Floating-point (decimal)
let price = 19.99;
let tiny = 0.001;
// Scientific notation
let big = 5e6; // 5,000,000
let small = 5e-6; // 0.000005
// Binary, Octal, Hexadecimal
let binary = 0b1010; // 10 in decimal
let octal = 0o755; // 493 in decimal
let hex = 0xff; // 255 in decimal
Special Number Values:
// Infinity
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity + 1); // Infinity
// NaN (Not a Number)
console.log('hello' * 2); // NaN
console.log(Math.sqrt(-1)); // NaN
console.log(NaN === NaN); // false (!) - NaN is not equal to itself
// Checking for NaN
console.log(isNaN(NaN)); // true
console.log(isNaN('hello')); // true (coerces to NaN)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false (doesn't coerce)
Number Precision:
// Safe integer range: -(2^53 - 1) to (2^53 - 1)
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991
// Precision issues with floating-point
console.log(0.1 + 0.2); // 0.30000000000000004 (not 0.3!)
console.log(0.1 + 0.2 === 0.3); // false
// How to compare floats safely
const a = 0.1 + 0.2;
const b = 0.3;
console.log(Math.abs(a - b) < Number.EPSILON); // true
// Number limits
console.log(Number.MAX_VALUE); // ~1.79e+308
console.log(Number.MIN_VALUE); // ~5e-324 (smallest positive)
Number Methods:
// Converting to Number
Number('42'); // 42
Number('3.14'); // 3.14
Number('hello'); // NaN
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN
// Parsing
parseInt('42'); // 42
parseInt('42.9'); // 42 (truncates decimal)
parseInt('42px'); // 42 (parses until non-digit)
parseInt('px42'); // NaN (starts with non-digit)
parseFloat('3.14'); // 3.14
parseFloat('3.14.15'); // 3.14 (stops at second dot)
// Formatting
let num = 3.14159;
num.toFixed(2); // "3.14" (string!)
num.toPrecision(4); // "3.142" (string!)
num.toString(); // "3.14159"
num.toString(2); // "11.001..." (binary string)
num.toString(16); // "3.243..." (hex string)
// Checking
Number.isInteger(42); // true
Number.isInteger(42.0); // true
Number.isInteger(42.5); // false
Number.isFinite(42); // true
Number.isFinite(Infinity); // false
String
Strings are sequences of characters used to represent text. They are immutable in JavaScript.
Creating Strings:
// Single quotes
let single = 'Hello';
// Double quotes
let double = 'World';
// Template literals (backticks) - ES6
let template = `Hello World`;
// Template literals with expressions
let name = 'John';
let greeting = `Hello, ${name}!`; // "Hello, John!"
// Multi-line strings
let multiLine = `Line 1
Line 2
Line 3`;
// Escape sequences
let escaped = 'He said "Hello"';
let newline = 'Line1\nLine2';
let tab = 'Col1\tCol2';
String Properties and Methods:
let str = 'Hello, World!';
// Length
str.length; // 13
// Access characters
str[0]; // "H"
str.charAt(0); // "H"
str.at(-1); // "!" (negative index, ES2022)
// Case conversion
str.toUpperCase(); // "HELLO, WORLD!"
str.toLowerCase(); // "hello, world!"
// Searching
str.indexOf('World'); // 7
str.lastIndexOf('o'); // 8
str.includes('World'); // true
str.startsWith('Hello'); // true
str.endsWith('!'); // true
// Extracting
str.slice(0, 5); // "Hello"
str.slice(-6); // "World!"
str.substring(0, 5); // "Hello"
str.substr(0, 5); // "Hello" (deprecated)
// Modifying (returns new string)
str.replace('World', 'JS'); // "Hello, JS!"
str.replaceAll('o', '0'); // "Hell0, W0rld!"
str.trim(); // Removes whitespace from ends
str.padStart(20, '*'); // "*******Hello, World!"
str.padEnd(20, '*'); // "Hello, World!*******"
str.repeat(2); // "Hello, World!Hello, World!"
// Splitting
str.split(', '); // ["Hello", "World!"]
str.split(''); // ["H", "e", "l", "l", "o", ...]
Template Literals (Template Strings):
// Basic interpolation
let name = 'Alice';
let age = 30;
console.log(`${name} is ${age} years old`);
// Expressions in templates
let a = 5;
let b = 10;
console.log(`Sum: ${a + b}`); // "Sum: 15"
console.log(`Comparison: ${a > b}`); // "Comparison: false"
// Function calls in templates
function greet(name) {
return `Hello, ${name}!`;
}
console.log(`Greeting: ${greet('Bob')}`);
// Multi-line
let html = `
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
`;
// Tagged templates (advanced)
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return `${result}${str}<mark>${values[i] || ''}</mark>`;
}, '');
}
let user = 'John';
let action = 'logged in';
console.log(highlight`User ${user} has ${action}`);
Immutability:
let str = 'Hello';
str[0] = 'Y'; // Doesn't work (no error, but no change)
console.log(str); // "Hello" (unchanged)
// To "modify", create a new string
str = 'Y' + str.slice(1);
console.log(str); // "Yello"
Boolean
Booleans represent logical values: true or false.
Creating Booleans:
let isActive = true;
let isComplete = false;
// From comparison
let isEqual = 5 === 5; // true
let isGreater = 10 > 5; // true
let isLess = 3 < 1; // false
// From Boolean() conversion
Boolean(1); // true
Boolean(0); // false
Boolean('hello'); // true
Boolean(''); // false
Truthy and Falsy Values:
JavaScript converts values to boolean in logical contexts. Some values are "falsy" (convert to false), all others are "truthy".
// FALSY VALUES (only these 8):
Boolean(false); // false
Boolean(0); // false
Boolean(-0); // false
Boolean(0n); // false (BigInt zero)
Boolean(''); // false (empty string)
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false
// TRUTHY VALUES (everything else):
Boolean(true); // true
Boolean(1); // true
Boolean(-1); // true
Boolean('hello'); // true
Boolean('false'); // true (non-empty string!)
Boolean([]); // true (empty array!)
Boolean({}); // true (empty object!)
Boolean(function () {}); // true
Practical Use of Truthy/Falsy:
// Conditional checks
let name = '';
if (name) {
console.log('Has name');
} else {
console.log('No name'); // This runs
}
// Default values (before ES6)
function greet(name) {
name = name || 'Guest'; // If falsy, use "Guest"
return `Hello, ${name}!`;
}
// Double negation to convert to boolean
let value = 'hello';
let boolValue = !!value; // true
// Common patterns
let items = [];
if (items.length) {
console.log('Has items');
} else {
console.log('Empty'); // This runs
}
Null
null represents the intentional absence of any value. It's explicitly assigned to indicate "no value" or "empty".
Understanding Null:
let user = null; // Intentionally set to "no value"
console.log(user); // null
console.log(typeof null); // "object" (this is a historical bug!)
// Checking for null
console.log(user === null); // true
console.log(user == null); // true
Null vs Undefined:
let a = null; // Intentionally empty
let b; // Not yet assigned (undefined)
let c = undefined; // Explicitly set to undefined (unusual)
console.log(a); // null
console.log(b); // undefined
// Equality checks
console.log(null == undefined); // true (loose equality)
console.log(null === undefined); // false (strict equality)
// Type checks
console.log(typeof null); // "object" (bug)
console.log(typeof undefined); // "undefined"
When to Use Null:
// Use null to indicate intentional absence
let selectedUser = null; // No user selected yet
function findUser(id) {
// Return null if user not found
if (/* user not found */) {
return null;
}
return { id: id, name: "John" };
}
let user = findUser(123);
if (user === null) {
console.log("User not found");
}
// Clear a variable
let data = { name: "test" };
data = null; // Clear the reference
Undefined
undefined means a variable has been declared but not assigned a value.
When Undefined Occurs:
// 1. Declared but not initialized
let x;
console.log(x); // undefined
// 2. Missing function parameters
function greet(name) {
console.log(name);
}
greet(); // undefined
// 3. Non-existent object properties
let obj = { a: 1 };
console.log(obj.b); // undefined
// 4. Functions without return
function noReturn() {
let x = 5;
}
console.log(noReturn()); // undefined
// 5. Array elements that don't exist
let arr = [1, 2, 3];
console.log(arr[10]); // undefined
Checking for Undefined:
let x;
// Method 1: Strict equality
if (x === undefined) {
console.log('x is undefined');
}
// Method 2: typeof (safer for undeclared variables)
if (typeof x === 'undefined') {
console.log('x is undefined');
}
// Method 3: Void operator comparison
if (x === void 0) {
console.log('x is undefined');
}
Null vs Undefined - When to Use Which:
// Use UNDEFINED when:
// - Variable hasn't been assigned yet
// - Property doesn't exist
// - Function has no return value
// - Parameter wasn't provided
// Use NULL when:
// - Intentionally setting "no value"
// - Clearing a reference
// - Indicating "not found"
// - API responses for missing data
// Common pattern
function getUser(id) {
if (id === undefined) {
throw new Error('ID is required'); // Parameter missing
}
let user = database.find(id);
return user || null; // Return null if not found
}
Symbol
Symbol is a unique and immutable primitive value, introduced in ES6. Used for creating unique identifiers.
Creating Symbols:
// Create a symbol
let sym1 = Symbol();
let sym2 = Symbol();
console.log(sym1 === sym2); // false (always unique!)
// Symbols with descriptions (for debugging)
let id = Symbol('id');
let id2 = Symbol('id');
console.log(id === id2); // false (still unique!)
console.log(id.description); // "id"
Why Use Symbols?
1. Unique Property Keys:
// Prevent property name collisions
const ID = Symbol('id');
const NAME = Symbol('name');
let user = {
[ID]: 12345,
[NAME]: 'John',
name: 'Regular name property',
};
console.log(user[ID]); // 12345
console.log(user[NAME]); // "John"
console.log(user.name); // "Regular name property"
// Symbols are not enumerable by default
console.log(Object.keys(user)); // ["name"]
console.log(Object.getOwnPropertySymbols(user)); // [Symbol(id), Symbol(name)]
2. Well-Known Symbols (Built-in):
// Symbol.iterator - define how object is iterated
let range = {
start: 1,
end: 5,
[Symbol.iterator]() {
let current = this.start;
let end = this.end;
return {
next() {
if (current <= end) {
return { value: current++, done: false };
}
return { done: true };
},
};
},
};
for (let num of range) {
console.log(num); // 1, 2, 3, 4, 5
}
// Symbol.toStringTag - customize Object.prototype.toString
class MyClass {
get [Symbol.toStringTag]() {
return 'MyClass';
}
}
console.log(Object.prototype.toString.call(new MyClass())); // "[object MyClass]"
3. Global Symbol Registry:
// Create/retrieve global symbols
let globalSym = Symbol.for('shared');
let sameGlobalSym = Symbol.for('shared');
console.log(globalSym === sameGlobalSym); // true (same symbol!)
// Get the key for a global symbol
console.log(Symbol.keyFor(globalSym)); // "shared"
// Regular symbols are not in the global registry
let localSym = Symbol('local');
console.log(Symbol.keyFor(localSym)); // undefined
BigInt
BigInt can represent integers of arbitrary size, beyond the safe integer limit of Number.
Creating BigInt:
// Add 'n' suffix
let big = 9007199254740991n;
let huge = 123456789012345678901234567890n;
// Using BigInt() constructor
let fromNumber = BigInt(9007199254740991);
let fromString = BigInt('9007199254740991');
console.log(typeof big); // "bigint"
BigInt Operations:
// Arithmetic works with BigInt
let a = 100n;
let b = 50n;
console.log(a + b); // 150n
console.log(a - b); // 50n
console.log(a * b); // 5000n
console.log(a / b); // 2n (truncates to integer)
console.log(a % b); // 0n
// Comparison works
console.log(a > b); // true
console.log(a === 100n); // true
// But NOT with Number (mixing types)
// console.log(a + 50); // TypeError!
console.log(a + BigInt(50)); // 150n (convert first)
BigInt Limitations:
// Cannot use with Math methods
// Math.max(1n, 2n); // TypeError
// Cannot have decimals
// let decimal = 1.5n; // SyntaxError
// Division truncates (no decimals)
console.log(5n / 2n); // 2n (not 2.5n)
// JSON doesn't support BigInt directly
// JSON.stringify({ big: 1n }); // TypeError
// Workaround:
JSON.stringify({ big: 1n.toString() });
// Loose equality with Number works
console.log(1n == 1); // true
console.log(1n === 1); // false (different types)
When to Use BigInt:
// Working with large IDs
const userId = 9007199254740993n;
// Cryptocurrency amounts (in smallest units)
const satoshis = 100000000n; // 1 Bitcoin
// Financial calculations requiring precision
const cents = 99999999999999999n;
// Timestamps in microseconds
const microseconds = 1638360000000000n;
Object (Reference Type)
While this section focuses on primitives, it's important to understand that Object is the only reference type, and it includes arrays and functions.
Objects Overview:
// Object literal
let person = {
name: 'John',
age: 30,
};
// Array (special object)
let numbers = [1, 2, 3];
// Function (callable object)
function greet() {
return 'Hello';
}
// Checking types
console.log(typeof person); // "object"
console.log(typeof numbers); // "object"
console.log(typeof greet); // "function"
console.log(Array.isArray(numbers)); // true
Reference Behavior:
// Objects are passed by reference
let original = { x: 10 };
let copy = original;
copy.x = 20;
console.log(original.x); // 20 (both point to same object!)
// To create a true copy:
let shallowCopy = { ...original }; // Shallow copy
let deepCopy = JSON.parse(JSON.stringify(original)); // Deep copy (limitations)
Type Checking
Using typeof:
console.log(typeof 42); // "number"
console.log(typeof 'hello'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object" (bug!)
console.log(typeof Symbol()); // "symbol"
console.log(typeof 42n); // "bigint"
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function () {}); // "function"
Better Type Checking:
// Check for null specifically
let value = null;
console.log(value === null); // true
// Check for array
Array.isArray([1, 2, 3]); // true
Array.isArray('hello'); // false
// Check for NaN
Number.isNaN(NaN); // true
Number.isNaN('hello'); // false
// Object.prototype.toString for accurate type
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(getType(42)); // "Number"
console.log(getType('hello')); // "String"
console.log(getType(null)); // "Null"
console.log(getType(undefined)); // "Undefined"
console.log(getType([])); // "Array"
console.log(getType({})); // "Object"
console.log(getType(/regex/)); // "RegExp"
console.log(getType(new Date())); // "Date"
šÆ Key Takeaways
- ā¢7 Primitive Types: Number, String, Boolean, Null, Undefined, Symbol, BigInt
- ā¢1 Reference Type: Object (includes Arrays and Functions)
- ā¢Primitives are immutable and copied by value
- ā¢Objects are mutable and copied by reference
- ā¢null = intentional absence, undefined = not yet assigned
- ā¢Symbol creates unique identifiers
- ā¢BigInt handles integers beyond safe range
- ā¢Use typeof for basic checks, but know its quirks (null returns "object")
ā”ļø Next Topic
Continue to 2.3 Type Mechanics to learn about type coercion, casting, and more!