Skip to main content
Advertisement

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"
Advertisement