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.
// 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.
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
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
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
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
// 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.
// 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.
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.
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.
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
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
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
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
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.
// 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.
// 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.
// 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.
// 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, nokeys(),values()) - No
sizeproperty orclear()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.
// 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.
// 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.
// 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.