2.2 Data Types
JavaScript's Type System
JavaScript is a dynamically typed language. Variables themselves have no type — values have types.
let variable = 42; // number
variable = "text"; // string (type changes!)
variable = true; // boolean
variable = null; // null
variable = { name: "JS" }; // object
7 Primitive Types
JavaScript's primitive types are immutable and compared by value.
1. string
// Three ways to declare
const single = 'single quotes';
const double = "double quotes";
const template = `template literal`; // ES6+
// Escape sequences
const newline = "line break\nhere";
const tab = "tab\there";
// Template literals (backticks)
const name = "Alice";
const age = 25;
const greeting = `Hello, ${name}! Age: ${age}`;
console.log(greeting); // "Hello, Alice! Age: 25"
// Key string methods
const str = "Hello, World!";
console.log(str.length); // 13
console.log(str.toUpperCase()); // "HELLO, WORLD!"
console.log(str.includes("World")); // true
console.log(str.slice(7, 12)); // "World"
console.log(str.replace("World", "JS")); // "Hello, JS!"
console.log(str.split(", ")); // ["Hello", "World!"]
console.log(" spaces ".trim()); // "spaces"
2. number
JavaScript has a single number type for both integers and decimals. It uses IEEE 754 double-precision 64-bit floating-point format.
const integer = 42;
const float = 3.14;
// Special values
console.log(Infinity); // Positive infinity
console.log(-Infinity); // Negative infinity
console.log(NaN); // Not a Number
// NaN check (== comparison won't work!)
console.log(NaN === NaN); // false (NaN is not equal to itself!)
console.log(Number.isNaN(NaN)); // true (correct way)
// Floating-point precision issue
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false (!)
// Solution: use Number.EPSILON
const a = 0.1 + 0.2;
const b = 0.3;
console.log(Math.abs(a - b) < Number.EPSILON); // true
// Numeric separator (ES2021+)
const million = 1_000_000; // Easier to read
3. bigint
number cannot accurately represent integers larger than 2^53-1. bigint handles arbitrarily large integers accurately.
// Create bigint with n suffix
const big = 9007199254740993n;
const huge = BigInt("123456789012345678901234567890");
console.log(typeof big); // "bigint"
// Operations
console.log(1n + 2n); // 3n
console.log(10n / 3n); // 3n (integer division, no decimals)
// Cannot mix bigint and number
console.log(1n + 1); // TypeError: Cannot mix BigInt and other types
4. boolean
const isTrue = true;
const isFalse = false;
// Falsy values (become false when converted to boolean):
console.log(Boolean(false)); // false
console.log(Boolean(0)); // false
console.log(Boolean("")); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false
// Everything else is Truthy:
console.log(Boolean("0")); // true (string "0" is truthy!)
console.log(Boolean([])); // true (empty array is truthy!)
console.log(Boolean({})); // true (empty object is truthy!)
5. null — Intentional absence
let user = null; // User not logged in yet
console.log(typeof null); // "object" (historical bug! null is not an object)
console.log(null === null); // true
console.log(null == undefined); // true (loose comparison)
console.log(null === undefined); // false (strict comparison)
6. undefined — Not initialized
let uninitialized;
console.log(uninitialized); // undefined
console.log(typeof uninitialized); // "undefined"
// Function with no return value
function noReturn() {}
console.log(noReturn()); // undefined
// Non-existent object property
const obj = {};
console.log(obj.missing); // undefined
7. symbol — Unique identifier
const sym1 = Symbol("description");
const sym2 = Symbol("description");
console.log(sym1 === sym2); // false (always unique!)
// Used as unique object keys
const ID = Symbol('id');
const user = {
name: "Alice",
[ID]: 12345, // Symbol as key
};
console.log(user[ID]); // 12345
// Symbol keys are hidden from for...in and Object.keys
console.log(Object.keys(user)); // ["name"] (no ID)
typeof Operator
console.log(typeof "hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof 42n); // "bigint"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof Symbol()); // "symbol"
console.log(typeof null); // "object" ← historical bug!
console.log(typeof {}); // "object"
console.log(typeof []); // "object" ← arrays are also objects
console.log(typeof function(){}); // "function"
Reference Types
All values other than primitives are reference types.
// Primitive: copies the value
let a = 10;
let b = a;
b = 20;
console.log(a); // 10 (unaffected)
// Reference: copies the reference (address)
const arr1 = [1, 2, 3];
const arr2 = arr1; // Points to the same array
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4] (arr1 also changed!)
// Shallow copy
const original = [1, 2, 3];
const copy = [...original];
copy.push(4);
console.log(original); // [1, 2, 3] (unaffected)
Pro Tips
Complete Type Checking Guide
// Checking types
const isString = (v) => typeof v === 'string';
const isNumber = (v) => typeof v === 'number' && !isNaN(v);
const isNull = (v) => v === null; // typeof won't work!
const isArray = (v) => Array.isArray(v);
// Most accurate type check
const getType = (v) => Object.prototype.toString.call(v).slice(8, -1).toLowerCase();
console.log(getType([])); // "array"
console.log(getType({})); // "object"
console.log(getType(null)); // "null"
console.log(getType(new Date())); // "date"