Data Structures

55 min read Beginner

Learn to work with JavaScript's built-in data structures: Arrays for ordered collections and Objects for key-value storage.

Introduction to Arrays

Arrays are ordered collections of values. They can hold any data type and are one of the most commonly used data structures in JavaScript.

JavaScript
// Creating arrays
const fruits = ["apple", "banana", "orange"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "two", true, null, { name: "John" }];
const empty = [];

// Array constructor (less common)
const arr = new Array(3); // Creates array with 3 empty slots
const arr2 = new Array(1, 2, 3); // Creates [1, 2, 3]

console.log(fruits);  // Output: ["apple", "banana", "orange"]
console.log(numbers); // Output: [1, 2, 3, 4, 5]

Accessing Array Elements

Array elements are accessed using zero-based indices. The first element is at index 0, the second at index 1, and so on.

JavaScript
const colors = ["red", "green", "blue", "yellow"];

// Accessing elements by index
console.log(colors[0]); // Output: "red"
console.log(colors[1]); // Output: "green"
console.log(colors[2]); // Output: "blue"

// Last element
console.log(colors[colors.length - 1]); // Output: "yellow"

// Using at() method (ES2022) - supports negative indices
console.log(colors.at(0));  // Output: "red"
console.log(colors.at(-1)); // Output: "yellow" (last element)
console.log(colors.at(-2)); // Output: "blue" (second to last)

// Accessing non-existent index
console.log(colors[10]); // Output: undefined

// Array length
console.log(colors.length); // Output: 4

// Modifying elements
colors[0] = "crimson";
console.log(colors); // Output: ["crimson", "green", "blue", "yellow"]

Basic Array Methods

JavaScript arrays come with many built-in methods for adding, removing, and manipulating elements.

Adding Elements

JavaScript
const fruits = ["apple", "banana"];

// push() - Add to end (returns new length)
fruits.push("orange");
console.log(fruits); // ["apple", "banana", "orange"]

// Add multiple items
fruits.push("grape", "mango");
console.log(fruits); // ["apple", "banana", "orange", "grape", "mango"]

// unshift() - Add to beginning (returns new length)
fruits.unshift("strawberry");
console.log(fruits); // ["strawberry", "apple", "banana", "orange", "grape", "mango"]

// Add at specific index using splice()
const colors = ["red", "blue"];
colors.splice(1, 0, "green"); // At index 1, remove 0, insert "green"
console.log(colors); // ["red", "green", "blue"]

Removing Elements

JavaScript
const fruits = ["apple", "banana", "orange", "grape", "mango"];

// pop() - Remove from end (returns removed element)
const last = fruits.pop();
console.log(last);   // "mango"
console.log(fruits); // ["apple", "banana", "orange", "grape"]

// shift() - Remove from beginning (returns removed element)
const first = fruits.shift();
console.log(first);  // "apple"
console.log(fruits); // ["banana", "orange", "grape"]

// splice() - Remove at specific index
// splice(startIndex, deleteCount)
const removed = fruits.splice(1, 1); // At index 1, remove 1 element
console.log(removed); // ["orange"]
console.log(fruits);  // ["banana", "grape"]

// Remove multiple elements
const numbers = [1, 2, 3, 4, 5];
numbers.splice(1, 3); // Remove 3 elements starting at index 1
console.log(numbers); // [1, 5]

Finding Elements

JavaScript
const fruits = ["apple", "banana", "orange", "banana", "grape"];

// indexOf() - Find first occurrence (returns -1 if not found)
console.log(fruits.indexOf("banana"));  // 1
console.log(fruits.indexOf("mango"));   // -1

// lastIndexOf() - Find last occurrence
console.log(fruits.lastIndexOf("banana")); // 3

// includes() - Check if element exists (returns boolean)
console.log(fruits.includes("orange")); // true
console.log(fruits.includes("mango"));  // false

// find() - Find first element matching a condition
const numbers = [1, 5, 10, 15, 20];
const found = numbers.find(num => num > 8);
console.log(found); // 10

// findIndex() - Find index of first matching element
const index = numbers.findIndex(num => num > 8);
console.log(index); // 2

// findLast() and findLastIndex() (ES2023)
const lastLarge = numbers.findLast(num => num > 8);
console.log(lastLarge); // 20

Other Useful Methods

JavaScript
// slice() - Extract a portion (doesn't modify original)
const fruits = ["apple", "banana", "orange", "grape", "mango"];
const sliced = fruits.slice(1, 4); // From index 1 to 4 (exclusive)
console.log(sliced); // ["banana", "orange", "grape"]
console.log(fruits); // Original unchanged

// concat() - Combine arrays
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]

// join() - Convert to string
const words = ["Hello", "World"];
console.log(words.join(" ")); // "Hello World"
console.log(words.join("-")); // "Hello-World"
console.log(words.join(""));  // "HelloWorld"

// reverse() - Reverse array (modifies original)
const nums = [1, 2, 3, 4, 5];
nums.reverse();
console.log(nums); // [5, 4, 3, 2, 1]

// sort() - Sort array (modifies original)
const letters = ["d", "b", "a", "c"];
letters.sort();
console.log(letters); // ["a", "b", "c", "d"]

// Sorting numbers (needs compare function!)
const numbers = [10, 2, 5, 1, 9];
numbers.sort((a, b) => a - b); // Ascending
console.log(numbers); // [1, 2, 5, 9, 10]

numbers.sort((a, b) => b - a); // Descending
console.log(numbers); // [10, 9, 5, 2, 1]

Introduction to Objects

Objects are collections of key-value pairs. They're used to store structured data and represent real-world entities with properties and behaviors.

JavaScript
// Creating objects with object literal syntax
const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30,
    isEmployed: true,
    hobbies: ["reading", "gaming", "hiking"],
    address: {
        street: "123 Main St",
        city: "New York",
        country: "USA"
    }
};

console.log(person);

// Empty object
const empty = {};

// Object with methods
const calculator = {
    add: function(a, b) {
        return a + b;
    },
    // Shorthand method syntax
    subtract(a, b) {
        return a - b;
    }
};

console.log(calculator.add(5, 3));      // 8
console.log(calculator.subtract(10, 4)); // 6

Accessing Object Properties

There are two ways to access object properties: dot notation and bracket notation.

JavaScript
const person = {
    firstName: "John",
    lastName: "Doe",
    age: 30,
    "favorite color": "blue" // Property with space
};

// Dot notation (preferred when possible)
console.log(person.firstName); // "John"
console.log(person.age);       // 30

// Bracket notation (required for special characters/spaces)
console.log(person["firstName"]);      // "John"
console.log(person["favorite color"]); // "blue"

// Dynamic property access
const prop = "lastName";
console.log(person[prop]); // "Doe"

// Nested properties
const user = {
    name: "Alice",
    address: {
        city: "Boston",
        zip: "02101"
    }
};

console.log(user.address.city);    // "Boston"
console.log(user["address"]["zip"]); // "02101"

// Accessing non-existent property
console.log(person.salary); // undefined

// Optional chaining (?.) - safe access
const data = { user: null };
console.log(data.user?.name); // undefined (no error!)
console.log(data.user.name);  // Error: Cannot read property 'name' of null

Modifying Objects

You can add, update, and delete properties from objects after they're created.

JavaScript
const person = {
    name: "John",
    age: 30
};

// Adding new properties
person.email = "john@example.com";
person["phone"] = "555-1234";
console.log(person);
// { name: "John", age: 30, email: "john@example.com", phone: "555-1234" }

// Updating existing properties
person.age = 31;
person.name = "John Smith";
console.log(person.age);  // 31
console.log(person.name); // "John Smith"

// Deleting properties
delete person.phone;
console.log(person.phone); // undefined
console.log(person);
// { name: "John Smith", age: 31, email: "john@example.com" }

// Checking if property exists
console.log("email" in person);    // true
console.log("phone" in person);    // false
console.log(person.hasOwnProperty("name")); // true

Object Methods

JavaScript provides several useful methods for working with objects.

JavaScript
const person = {
    name: "Alice",
    age: 25,
    city: "Boston"
};

// Object.keys() - Get array of keys
const keys = Object.keys(person);
console.log(keys); // ["name", "age", "city"]

// Object.values() - Get array of values
const values = Object.values(person);
console.log(values); // ["Alice", 25, "Boston"]

// Object.entries() - Get array of [key, value] pairs
const entries = Object.entries(person);
console.log(entries);
// [["name", "Alice"], ["age", 25], ["city", "Boston"]]

// Object.fromEntries() - Create object from entries
const arr = [["a", 1], ["b", 2], ["c", 3]];
const obj = Object.fromEntries(arr);
console.log(obj); // { a: 1, b: 2, c: 3 }

// Object.assign() - Copy/merge objects
const defaults = { theme: "light", fontSize: 14 };
const userPrefs = { fontSize: 16 };
const settings = Object.assign({}, defaults, userPrefs);
console.log(settings); // { theme: "light", fontSize: 16 }

// Spread operator (modern alternative to assign)
const merged = { ...defaults, ...userPrefs };
console.log(merged); // { theme: "light", fontSize: 16 }

// Object.freeze() - Prevent modifications
const frozen = Object.freeze({ x: 1, y: 2 });
frozen.x = 100;  // Silently fails (or throws in strict mode)
frozen.z = 3;    // Also fails
console.log(frozen); // { x: 1, y: 2 }

// Object.seal() - Prevent adding/deleting, but allow updates
const sealed = Object.seal({ a: 1, b: 2 });
sealed.a = 100;  // Works!
sealed.c = 3;    // Fails
delete sealed.b; // Fails
console.log(sealed); // { a: 100, b: 2 }

Iterating Over Data Structures

There are multiple ways to iterate over arrays and objects in JavaScript.

Iterating Arrays

JavaScript
const fruits = ["apple", "banana", "orange"];

// for loop
for (let i = 0; i < fruits.length; i++) {
    console.log(i, fruits[i]);
}

// for...of (recommended for arrays)
for (const fruit of fruits) {
    console.log(fruit);
}

// forEach method
fruits.forEach((fruit, index) => {
    console.log(index, fruit);
});

// forEach with just value
fruits.forEach(fruit => console.log(fruit));

// Using entries() for index and value
for (const [index, fruit] of fruits.entries()) {
    console.log(index, fruit);
}

Iterating Objects

JavaScript
const person = {
    name: "John",
    age: 30,
    city: "New York"
};

// for...in loop (for objects)
for (const key in person) {
    console.log(key, person[key]);
}
// Output:
// name John
// age 30
// city New York

// Using Object.keys()
Object.keys(person).forEach(key => {
    console.log(key, person[key]);
});

// Using Object.values()
for (const value of Object.values(person)) {
    console.log(value);
}

// Using Object.entries() (recommended)
for (const [key, value] of Object.entries(person)) {
    console.log(`${key}: ${value}`);
}

// With forEach
Object.entries(person).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
});

Destructuring

Destructuring is a convenient way to extract values from arrays and objects into separate variables.

Array Destructuring

JavaScript
const colors = ["red", "green", "blue", "yellow"];

// Basic destructuring
const [first, second] = colors;
console.log(first);  // "red"
console.log(second); // "green"

// Skip elements
const [, , third] = colors;
console.log(third); // "blue"

// Rest pattern
const [primary, ...others] = colors;
console.log(primary); // "red"
console.log(others);  // ["green", "blue", "yellow"]

// Default values
const [a, b, c, d, e = "purple"] = colors;
console.log(e); // "purple"

// Swapping variables
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1

// From function returns
function getCoordinates() {
    return [10, 20];
}
const [xCoord, yCoord] = getCoordinates();
console.log(xCoord, yCoord); // 10 20

Object Destructuring

JavaScript
const person = {
    name: "John",
    age: 30,
    city: "New York",
    country: "USA"
};

// Basic destructuring
const { name, age } = person;
console.log(name); // "John"
console.log(age);  // 30

// Rename variables
const { name: userName, city: userCity } = person;
console.log(userName); // "John"
console.log(userCity); // "New York"

// Default values
const { name: n, salary = 50000 } = person;
console.log(salary); // 50000

// Rest pattern
const { name: personName, ...rest } = person;
console.log(personName); // "John"
console.log(rest);       // { age: 30, city: "New York", country: "USA" }

// Nested destructuring
const user = {
    id: 1,
    profile: {
        username: "johndoe",
        email: "john@example.com"
    }
};

const { profile: { username, email } } = user;
console.log(username); // "johndoe"
console.log(email);    // "john@example.com"

// In function parameters
function greet({ name, age }) {
    console.log(`Hello ${name}, you are ${age} years old`);
}

greet(person); // "Hello John, you are 30 years old"

Spread Operator

The spread operator (...) expands arrays and objects into individual elements.

JavaScript
// Spreading arrays
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// Combining arrays
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]

// Copying arrays
const copy = [...arr1];
copy.push(4);
console.log(arr1); // [1, 2, 3] (unchanged)
console.log(copy); // [1, 2, 3, 4]

// Adding elements
const withExtra = [0, ...arr1, 4];
console.log(withExtra); // [0, 1, 2, 3, 4]

// Spreading in function calls
const numbers = [5, 2, 8, 1, 9];
console.log(Math.max(...numbers)); // 9
console.log(Math.min(...numbers)); // 1

// Spreading objects
const defaults = {
    theme: "light",
    fontSize: 14,
    language: "en"
};

const userSettings = {
    fontSize: 16,
    darkMode: true
};

// Merge objects (later properties override earlier ones)
const settings = { ...defaults, ...userSettings };
console.log(settings);
// { theme: "light", fontSize: 16, language: "en", darkMode: true }

// Copying objects
const original = { a: 1, b: 2 };
const clone = { ...original };
clone.c = 3;
console.log(original); // { a: 1, b: 2 }
console.log(clone);    // { a: 1, b: 2, c: 3 }

// Adding/overriding properties
const product = { name: "Widget", price: 10 };
const updated = { ...product, price: 15, inStock: true };
console.log(updated);
// { name: "Widget", price: 15, inStock: true }

Spread Creates Shallow Copies

The spread operator creates a shallow copy. Nested objects/arrays are still referenced, not copied:

const original = { user: { name: "John" } };
const copy = { ...original };
copy.user.name = "Jane";
console.log(original.user.name); // "Jane" - original also changed!

Map and Set Data Structures

ES6 introduced Map and Set as new collection types that complement arrays and objects with unique capabilities.

Map - Key-Value Pairs with Any Key Type

Unlike objects, Maps can use any value as keys (including objects, functions, and primitives) and maintain insertion order.

JavaScript
// Creating a Map
const userRoles = new Map();

// Adding entries with set()
userRoles.set("john", "admin");
userRoles.set("jane", "editor");
userRoles.set("bob", "viewer");

// Using any type as key
const objKey = { id: 1 };
const funcKey = () => {};
userRoles.set(objKey, "object-based role");
userRoles.set(funcKey, "function-based role");

// Getting values
console.log(userRoles.get("john"));    // "admin"
console.log(userRoles.get(objKey));    // "object-based role"

// Checking existence
console.log(userRoles.has("jane"));    // true
console.log(userRoles.size);           // 5

// Deleting entries
userRoles.delete("bob");
console.log(userRoles.has("bob"));     // false

// Initialize with array of pairs
const settings = new Map([
    ["theme", "dark"],
    ["language", "en"],
    ["notifications", true]
]);

// Iterating over Map
for (const [key, value] of settings) {
    console.log(`${key}: ${value}`);
}

// Convert to array
const entries = [...settings];          // Array of [key, value] pairs
const keys = [...settings.keys()];      // ["theme", "language", "notifications"]
const values = [...settings.values()];  // ["dark", "en", true]

// Clear all entries
settings.clear();
console.log(settings.size);             // 0

Set - Unique Values Collection

Sets store unique values of any type. They're perfect for removing duplicates and checking membership efficiently.

JavaScript
// Creating a Set
const uniqueNumbers = new Set();

// Adding values
uniqueNumbers.add(1);
uniqueNumbers.add(2);
uniqueNumbers.add(3);
uniqueNumbers.add(1);  // Duplicate - ignored
uniqueNumbers.add(2);  // Duplicate - ignored

console.log(uniqueNumbers.size);  // 3 (not 5!)
console.log([...uniqueNumbers]);  // [1, 2, 3]

// Initialize with array (removes duplicates!)
const tags = new Set(["javascript", "python", "javascript", "ruby"]);
console.log([...tags]);  // ["javascript", "python", "ruby"]

// Checking membership (O(1) - very fast!)
console.log(tags.has("javascript"));  // true
console.log(tags.has("go"));          // false

// Deleting values
tags.delete("python");
console.log(tags.has("python"));      // false

// Perfect for removing duplicates from array
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
const uniqueArray = [...new Set(numbers)];
console.log(uniqueArray);  // [1, 2, 3, 4]

// Set operations (manual implementation)
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);

// Union
const union = new Set([...setA, ...setB]);
console.log([...union]);  // [1, 2, 3, 4, 5, 6]

// Intersection
const intersection = new Set([...setA].filter(x => setB.has(x)));
console.log([...intersection]);  // [3, 4]

// Difference (A - B)
const difference = new Set([...setA].filter(x => !setB.has(x)));
console.log([...difference]);  // [1, 2]

// Iterating
for (const value of tags) {
    console.log(value);
}

When to Use Map vs Object

Use Map when: Keys are unknown at runtime, all keys are same type, you need key-value pairs with non-string keys, you need to iterate frequently, or you need to track size easily.

Use Object when: Keys are strings, you need JSON serialization, you have a fixed schema, or you're working with records/entities.

WeakMap and WeakSet

WeakMap and WeakSet are variants that hold "weak" references to objects, allowing garbage collection when objects are no longer needed elsewhere.

JavaScript
// WeakMap - keys MUST be objects
const privateData = new WeakMap();

// Using WeakMap for private data
class Person {
    constructor(name, age) {
        privateData.set(this, { name, age });
    }
    
    getName() {
        return privateData.get(this).name;
    }
    
    getAge() {
        return privateData.get(this).age;
    }
}

let person = new Person("John", 30);
console.log(person.getName());  // "John"
console.log(person.getAge());   // 30

// When person is dereferenced, WeakMap entry is automatically garbage collected
person = null;  // Data in WeakMap becomes eligible for GC

// WeakMap for caching expensive computations
const cache = new WeakMap();

function expensiveOperation(obj) {
    if (cache.has(obj)) {
        console.log("Cache hit!");
        return cache.get(obj);
    }
    
    console.log("Computing...");
    const result = /* expensive computation */ obj.value * 2;
    cache.set(obj, result);
    return result;
}

let data = { value: 21 };
console.log(expensiveOperation(data));  // "Computing..." -> 42
console.log(expensiveOperation(data));  // "Cache hit!" -> 42
data = null;  // Cache entry automatically cleaned up!

// WeakSet - stores unique object references
const visitedNodes = new WeakSet();

function processNode(node) {
    if (visitedNodes.has(node)) {
        console.log("Already processed");
        return;
    }
    
    visitedNodes.add(node);
    // Process the node...
    console.log("Processing:", node.id);
}

let node1 = { id: 1 };
let node2 = { id: 2 };

processNode(node1);  // "Processing: 1"
processNode(node2);  // "Processing: 2"
processNode(node1);  // "Already processed"

node1 = null;  // WeakSet entry automatically garbage collected

WeakMap/WeakSet Limitations

Due to their weak reference nature:

  • Keys must be objects (not primitives)
  • Not iterable (no for...of, no keys(), values())
  • No size property or clear() method
  • Cannot determine when entries are garbage collected

Array-Like Objects

Array-like objects have numbered indices and a length property but don't inherit Array methods. Common examples include arguments, NodeLists, and strings.

JavaScript
// The 'arguments' object (in regular functions)
function sum() {
    console.log(arguments);        // { 0: 1, 1: 2, 2: 3, length: 3 }
    console.log(arguments.length); // 3
    console.log(arguments[0]);     // 1
    
    // arguments.map() would fail - not a real array!
    // arguments.map(x => x * 2);  // TypeError!
    
    // Convert to array first
    const args = Array.from(arguments);
    // or: const args = [...arguments];
    
    return args.reduce((a, b) => a + b, 0);
}

console.log(sum(1, 2, 3));  // 6

// Better: Use rest parameters (creates real array)
function betterSum(...numbers) {
    return numbers.reduce((a, b) => a + b, 0);
}

// DOM NodeList is array-like
const divs = document.querySelectorAll('div');
console.log(divs.length);    // Works
console.log(divs[0]);        // Works
// divs.map(...);            // May fail in older browsers!

// Convert NodeList to array
const divArray = Array.from(divs);
// or: const divArray = [...divs];
divArray.forEach(div => console.log(div));

// Strings are array-like
const str = "Hello";
console.log(str.length);     // 5
console.log(str[0]);         // "H"
console.log([...str]);       // ["H", "e", "l", "l", "o"]

// Creating array-like objects
const arrayLike = {
    0: "a",
    1: "b", 
    2: "c",
    length: 3
};

console.log(arrayLike[1]);          // "b"
console.log(Array.from(arrayLike)); // ["a", "b", "c"]

// Array.from with mapping function
const arrayLikeNumbers = { 0: 1, 1: 2, 2: 3, length: 3 };
const doubled = Array.from(arrayLikeNumbers, x => x * 2);
console.log(doubled);  // [2, 4, 6]

// Checking if something is a real array
console.log(Array.isArray([1, 2, 3]));      // true
console.log(Array.isArray(arrayLike));       // false
console.log(Array.isArray("string"));        // false
console.log(Array.isArray(new Set([1,2]))); // false

Typed Arrays Introduction

Typed Arrays provide a mechanism for accessing raw binary data buffers. They're essential for WebGL, file processing, WebSockets, and performance-critical applications.

JavaScript
// Typed Array Types:
// Int8Array, Uint8Array, Uint8ClampedArray
// Int16Array, Uint16Array
// Int32Array, Uint32Array
// Float32Array, Float64Array
// BigInt64Array, BigUint64Array

// Creating typed arrays
const int8 = new Int8Array(4);        // 4 signed bytes
const uint8 = new Uint8Array(4);      // 4 unsigned bytes
const float32 = new Float32Array(4);  // 4 floats

// Initialize with values
const scores = new Uint8Array([85, 92, 78, 95]);
console.log(scores[0]);      // 85
console.log(scores.length);  // 4

// Typed arrays enforce their type!
const bytes = new Uint8Array([255, 256, -1]);
console.log([...bytes]);  // [255, 0, 255]
// 256 overflows to 0, -1 wraps to 255

// Uint8ClampedArray clamps values instead
const clamped = new Uint8ClampedArray([255, 300, -10]);
console.log([...clamped]);  // [255, 255, 0]
// Values clamped to 0-255 range

// Working with ArrayBuffer (raw binary data)
const buffer = new ArrayBuffer(16);  // 16 bytes of memory
console.log(buffer.byteLength);      // 16

// View the same buffer as different types
const view32 = new Int32Array(buffer);   // 4 x 32-bit integers
const view8 = new Uint8Array(buffer);    // 16 x 8-bit integers

view32[0] = 0x12345678;
console.log(view8[0].toString(16));  // "78" (little-endian)
console.log(view8[1].toString(16));  // "56"
console.log(view8[2].toString(16));  // "34"
console.log(view8[3].toString(16));  // "12"

// DataView for more control
const dataView = new DataView(buffer);
dataView.setInt32(0, 0x12345678, false);  // big-endian
dataView.setInt32(4, 0x12345678, true);   // little-endian
console.log(dataView.getInt32(0, false)); // 305419896

// Common use case: processing binary file
async function processImage(blob) {
    const arrayBuffer = await blob.arrayBuffer();
    const bytes = new Uint8Array(arrayBuffer);
    
    // Check PNG signature
    const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
    const isPng = pngSignature.every((byte, i) => bytes[i] === byte);
    console.log("Is PNG:", isPng);
}

// Performance comparison
const regularArray = new Array(1000000).fill(0);
const typedArray = new Float64Array(1000000);

console.time("Regular array");
for (let i = 0; i < regularArray.length; i++) {
    regularArray[i] = Math.sqrt(i);
}
console.timeEnd("Regular array");  // ~20ms

console.time("Typed array");
for (let i = 0; i < typedArray.length; i++) {
    typedArray[i] = Math.sqrt(i);
}
console.timeEnd("Typed array");    // ~5ms (much faster!)

When to Use Typed Arrays

  • WebGL/Canvas: For graphics and image manipulation
  • Audio/Video: Processing media streams
  • File I/O: Reading/writing binary files
  • WebSockets: Sending binary data
  • Scientific computing: When performance matters
  • Cryptography: Working with raw bytes

Choosing the Right Data Structure

Selecting the appropriate data structure is crucial for code clarity and performance.

JavaScript
// Decision Guide:

// ARRAY: Ordered list, numeric indices, duplicates OK
const todoList = ["Buy milk", "Walk dog", "Buy milk"]; // Order matters, duplicates OK
const queue = []; queue.push("a"); queue.shift();      // FIFO queue
const stack = []; stack.push("a"); stack.pop();        // LIFO stack

// OBJECT: Record with known string keys
const user = { id: 1, name: "John", email: "john@example.com" };
const config = { theme: "dark", language: "en" };

// MAP: Dynamic keys, any key type, ordered
const userSessions = new Map();
userSessions.set(userObject, sessionData);             // Object as key
const metadata = new Map();
metadata.set(Symbol("id"), 123);                       // Symbol as key

// SET: Unique values, fast membership testing
const visitedUrls = new Set();
visitedUrls.add("/home");
if (!visitedUrls.has("/about")) { /* navigate */ }

// WEAKMAP: Object keys with automatic cleanup
const domMetadata = new WeakMap();
domMetadata.set(element, { clicks: 0 });               // Auto-cleanup when element removed

// TYPED ARRAY: Binary data, numeric performance
const audioSamples = new Float32Array(44100);          // Audio processing
const imageData = new Uint8ClampedArray(width * height * 4); // RGBA pixels

// Performance characteristics (Big O):
// ┌─────────────────┬───────────┬───────────┬───────────┐
// │ Operation       │ Array     │ Object    │ Map/Set   │
// ├─────────────────┼───────────┼───────────┼───────────┤
// │ Access by index │ O(1)      │ N/A       │ N/A       │
// │ Access by key   │ O(n)      │ O(1)      │ O(1)      │
// │ Insert/Delete   │ O(n)*     │ O(1)      │ O(1)      │
// │ Search          │ O(n)      │ O(1)      │ O(1)      │
// │ Iteration       │ O(n)      │ O(n)      │ O(n)      │
// └─────────────────┴───────────┴───────────┴───────────┘
// * push/pop are O(1), shift/unshift are O(n)

Summary

Arrays

Ordered collections accessed by index. Use push/pop, shift/unshift, splice.

Objects

Key-value pairs accessed by dot or bracket notation. Use Object.keys/values/entries.

Iteration

for...of for arrays, for...in or Object.entries for objects.

Destructuring

Extract values: [a, b] = arr or { name } = obj.

Spread

Expand with ...: copy, merge, or pass as arguments.

Best Practices

Prefer const for arrays/objects, use modern methods, avoid mutation when possible.