JavaScript
A versatile, high-level programming language that enables dynamic, interactive web content and full-stack application development.
JavaScript Cheatsheet
A versatile, high-level programming language that enables dynamic, interactive web content and full-stack application development.
Overview
JavaScript is the backbone of modern web development, running in browsers and on servers via Node.js. It supports multiple programming paradigms including object-oriented, functional, and event-driven programming.
graph TB
subgraph "JavaScript Runtime Environment"
A[JavaScript Engine] --> B[Call Stack]
A --> C[Memory Heap]
subgraph "Event Loop"
D[Event Loop] --> E[Callback Queue]
D --> F[Microtask Queue]
end
G[Web APIs] --> E
B --> D
F --> B
E --> B
end
subgraph "Core Concepts"
H[Variables] --> I[Functions]
I --> J[Objects/Arrays]
J --> K[Async/Promises]
K --> L[DOM/Events]
end
style A fill:#f9d71c
style D fill:#61dafb
style K fill:#68d391
Variables and Data Types
Key Concepts
- let: Block-scoped variable that can be reassigned
- const: Block-scoped constant that cannot be reassigned (but objects/arrays can be mutated)
- var: Function-scoped variable (legacy, avoid in modern code)
- Hoisting: Variables declared with
varare hoisted;letandconsthave temporal dead zone - Primitive types: string, number, boolean, null, undefined, symbol, bigint
- Reference types: objects, arrays, functions
Common Patterns
// Variable declarations
let counter = 0; // Can be reassigned
const MAX_SIZE = 100; // Cannot be reassigned
var legacyVar = 'avoid'; // Function-scoped (legacy)
// Data types
const str = 'Hello'; // String
const num = 42; // Number
const bool = true; // Boolean
const nothing = null; // Null
const notDefined = undefined; // Undefined
const sym = Symbol('id'); // Symbol
const big = 9007199254740991n; // BigInt
// Type checking
typeof str; // 'string'
typeof num; // 'number'
typeof bool; // 'boolean'
typeof nothing; // 'object' (known quirk)
typeof notDefined; // 'undefined'
Array.isArray([1, 2, 3]); // true
// Type coercion
String(123); // '123'
Number('42'); // 42
Boolean(0); // false
parseInt('42px'); // 42
parseFloat('3.14'); // 3.14
Examples
// Block scoping demonstration
function scopeDemo() {
var funcScoped = 'I am function scoped';
if (true) {
let blockScoped = 'I am block scoped';
const alsoBlock = 'Me too';
var stillFunc = 'Still function scoped';
console.log(blockScoped); // Works
}
console.log(stillFunc); // Works
// console.log(blockScoped); // ReferenceError
}
// Temporal dead zone
console.log(x); // undefined (hoisted)
// console.log(y); // ReferenceError (TDZ)
var x = 5;
let y = 10;
// Const with objects (mutation allowed)
const user = { name: 'Alice' };
user.name = 'Bob'; // Allowed
user.age = 30; // Allowed
// user = {}; // TypeError - reassignment not allowed
Functions
Key Concepts
- Function declaration: Hoisted, can be called before definition
- Function expression: Not hoisted, assigned to a variable
- Arrow functions: Concise syntax, lexically bound
this - Callbacks: Functions passed as arguments to other functions
- Higher-order functions: Functions that take or return other functions
- Closures: Functions that remember their lexical scope
Common Patterns
// Function declaration
function greet(name) {
return `Hello, ${name}!`;
}
// Function expression
const greetExpr = function(name) {
return `Hello, ${name}!`;
};
// Arrow function
const greetArrow = (name) => `Hello, ${name}!`;
// Multiple parameters
const add = (a, b) => a + b;
// No parameters
const getRandom = () => Math.random();
// Multiple statements
const calculate = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};
// Default parameters
const greetWithDefault = (name = 'World') => `Hello, ${name}!`;
// Rest parameters
const sum = (...numbers) => numbers.reduce((acc, n) => acc + n, 0);
// Callback example
const fetchData = (callback) => {
setTimeout(() => {
callback('Data loaded');
}, 1000);
};
// IIFE (Immediately Invoked Function Expression)
(function() {
console.log('Executed immediately');
})();
Examples
// Closure example
function createCounter() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
// Arrow functions and 'this'
const obj = {
name: 'Object',
regularFunc: function() {
console.log(this.name); // 'Object'
},
arrowFunc: () => {
console.log(this.name); // undefined (lexical this)
},
methodWithCallback: function() {
// Arrow keeps 'this' context
setTimeout(() => {
console.log(this.name); // 'Object'
}, 100);
}
};
// Higher-order function
const withLogging = (fn) => {
return (...args) => {
console.log(`Calling with args: ${args}`);
const result = fn(...args);
console.log(`Result: ${result}`);
return result;
};
};
const loggedAdd = withLogging(add);
loggedAdd(2, 3); // Logs: "Calling with args: 2,3" then "Result: 5"
Objects and Arrays
Key Concepts
- Object literals: Key-value pairs enclosed in braces
- Destructuring: Extract values from objects/arrays into variables
- Spread operator: Expand iterables into individual elements
- Rest operator: Collect remaining elements into an array
- Object methods: Object.keys(), Object.values(), Object.entries()
- Array methods: Chainable methods for data transformation
Common Patterns
// Object creation
const user = {
name: 'Alice',
age: 30,
email: 'alice@example.com'
};
// Shorthand property names
const name = 'Bob';
const age = 25;
const person = { name, age }; // { name: 'Bob', age: 25 }
// Computed property names
const key = 'dynamicKey';
const obj = { [key]: 'value' };
// Object destructuring
const { name: userName, age: userAge } = user;
// Nested destructuring
const data = { user: { details: { city: 'London' } } };
const { user: { details: { city } } } = data;
// Default values in destructuring
const { country = 'UK' } = user;
// Array destructuring
const colours = ['red', 'green', 'blue'];
const [first, second, third] = colours;
const [primary, ...rest] = colours; // rest = ['green', 'blue']
// Spread operator
const newUser = { ...user, role: 'admin' };
const allColours = [...colours, 'yellow'];
// Object methods
Object.keys(user); // ['name', 'age', 'email']
Object.values(user); // ['Alice', 30, 'alice@example.com']
Object.entries(user); // [['name', 'Alice'], ['age', 30], ...]
Object.assign({}, user, { role: 'admin' });
// Optional chaining
const city = user?.address?.city; // undefined (no error)
// Nullish coalescing
const value = null ?? 'default'; // 'default'
const zero = 0 ?? 'default'; // 0
Examples
// Deep cloning
const original = { a: 1, b: { c: 2 } };
const clone = structuredClone(original);
// Legacy method (loses Dates, Maps, undefined, functions):
// JSON.parse(JSON.stringify(original))
// Merging objects
const defaults = { theme: 'light', language: 'en' };
const userPrefs = { theme: 'dark' };
const settings = { ...defaults, ...userPrefs };
// { theme: 'dark', language: 'en' }
// Array of objects manipulation
const users = [
{ id: 1, name: 'Alice', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Charlie', active: true }
];
// Find by property
const bob = users.find(u => u.name === 'Bob');
// Filter active users
const activeUsers = users.filter(u => u.active);
// Extract names
const names = users.map(u => u.name);
// Group by property (ES2024+)
const grouped = Object.groupBy(users, u => u.active ? 'active' : 'inactive');
// Swapping variables
let a = 1, b = 2;
[a, b] = [b, a]; // a = 2, b = 1
// Function parameter destructuring
const printUser = ({ name, age = 0 }) => {
console.log(`${name} is ${age} years old`);
};
printUser(user);
DOM Manipulation
Key Concepts
- Document Object Model (DOM): Tree representation of HTML
- Selectors: Methods to find elements in the DOM
- Element creation: Programmatically building DOM nodes
- Attributes and properties: Managing element data
- Traversal: Navigating the DOM tree
Common Patterns
// Selecting elements
const element = document.getElementById('myId');
const single = document.querySelector('.class');
const multiple = document.querySelectorAll('div.item');
// Creating elements
const div = document.createElement('div');
div.textContent = 'Hello World';
div.innerHTML = '<span>With HTML</span>';
// Setting attributes
div.id = 'myDiv';
div.className = 'container active';
div.classList.add('highlight');
div.classList.remove('active');
div.classList.toggle('visible');
div.setAttribute('data-id', '123');
// Getting attributes
const dataId = div.getAttribute('data-id');
const hasClass = div.classList.contains('container');
// Styles
div.style.backgroundColor = 'blue';
div.style.cssText = 'color: white; padding: 10px;';
// Inserting elements
document.body.appendChild(div);
parent.insertBefore(newElement, referenceElement);
element.append(child1, child2, 'text');
element.prepend(child);
element.before(sibling);
element.after(sibling);
// Removing elements
element.remove();
parent.removeChild(child);
// Cloning
const clone = element.cloneNode(true); // true = deep clone
// DOM traversal
element.parentElement;
element.children;
element.firstElementChild;
element.lastElementChild;
element.nextElementSibling;
element.previousElementSibling;
element.closest('.ancestor');
Examples
// Building a list dynamically
const items = ['Apple', 'Banana', 'Cherry'];
const ul = document.createElement('ul');
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
ul.appendChild(li);
});
document.body.appendChild(ul);
// Using DocumentFragment for performance
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
// Template literals for complex HTML
const createCard = (user) => {
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h2>${user.name}</h2>
<p>${user.email}</p>
<button data-id="${user.id}">View Profile</button>
`;
return card;
};
// Replacing content
const container = document.querySelector('#container');
container.replaceChildren(); // Clear all children
container.replaceChildren(...newElements); // Replace with new
Event Handling and Propagation
Key Concepts
- Event listeners: Functions that respond to user interactions
- Event bubbling: Events propagate up from target to ancestors
- Event capturing: Events propagate down from ancestors to target
- Event delegation: Handle events on parent for dynamic children
- Event object: Contains information about the event
graph TB
subgraph "Event Propagation Phases"
direction TB
A[Window] -->|1. Capture| B[Document]
B -->|1. Capture| C[Parent Element]
C -->|1. Capture| D[Target Element]
D -->|2. Target| D
D -->|3. Bubble| C
C -->|3. Bubble| B
B -->|3. Bubble| A
end
style D fill:#f9d71c
Common Patterns
// Adding event listeners
element.addEventListener('click', (event) => {
console.log('Clicked!', event.target);
});
// Removing event listeners
const handler = (event) => console.log(event);
element.addEventListener('click', handler);
element.removeEventListener('click', handler);
// Event options
element.addEventListener('click', handler, {
once: true, // Remove after first trigger
passive: true, // Won't call preventDefault()
capture: true // Use capture phase
});
// Common events
element.addEventListener('click', handler);
element.addEventListener('dblclick', handler);
element.addEventListener('mouseenter', handler);
element.addEventListener('mouseleave', handler);
element.addEventListener('keydown', handler);
element.addEventListener('keyup', handler);
element.addEventListener('submit', handler);
element.addEventListener('change', handler);
element.addEventListener('input', handler);
element.addEventListener('focus', handler);
element.addEventListener('blur', handler);
element.addEventListener('scroll', handler);
element.addEventListener('load', handler);
// Prevent default behaviour
form.addEventListener('submit', (e) => {
e.preventDefault();
// Handle form manually
});
// Stop propagation
element.addEventListener('click', (e) => {
e.stopPropagation(); // Stop bubbling
});
// Event object properties
element.addEventListener('click', (e) => {
e.target; // Element that triggered event
e.currentTarget; // Element with listener attached
e.type; // Event type ('click')
e.timeStamp; // When event occurred
e.clientX; // Mouse X coordinate
e.clientY; // Mouse Y coordinate
e.key; // Key pressed (for keyboard events)
});
Examples
// Event delegation
const list = document.querySelector('#todoList');
list.addEventListener('click', (e) => {
if (e.target.matches('.delete-btn')) {
const item = e.target.closest('li');
item.remove();
}
if (e.target.matches('.toggle-btn')) {
e.target.closest('li').classList.toggle('completed');
}
});
// Debouncing scroll/resize events
const debounce = (fn, delay) => {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
};
window.addEventListener('scroll', debounce(() => {
console.log('Scrolled!');
}, 250));
// Throttling for rate limiting
const throttle = (fn, limit) => {
let inThrottle;
return (...args) => {
if (!inThrottle) {
fn(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
};
// Custom events
const customEvent = new CustomEvent('userLoggedIn', {
detail: { userId: 123, username: 'alice' }
});
document.addEventListener('userLoggedIn', (e) => {
console.log('User logged in:', e.detail);
});
document.dispatchEvent(customEvent);
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.key === 's') {
e.preventDefault();
saveDocument();
}
});
Promises and Async Patterns
Key Concepts
- Promise: Object representing eventual completion/failure of async operation
- Promise states: pending, fulfilled, rejected
- then/catch/finally: Methods for handling promise results
- async/await: Syntactic sugar for working with promises
- Promise combinators: all, allSettled, race, any
stateDiagram-v2
[*] --> Pending
Pending --> Fulfilled: resolve(value)
Pending --> Rejected: reject(error)
Fulfilled --> [*]: .then(onFulfilled)
Rejected --> [*]: .catch(onRejected)
note right of Pending: Initial state
note right of Fulfilled: Operation succeeded
note right of Rejected: Operation failed
Common Patterns
// Creating a promise
const promise = new Promise((resolve, reject) => {
// Async operation
setTimeout(() => {
const success = true;
if (success) {
resolve('Operation successful');
} else {
reject(new Error('Operation failed'));
}
}, 1000);
});
// Consuming promises
promise
.then(result => {
console.log(result);
return 'Next value';
})
.then(nextResult => {
console.log(nextResult);
})
.catch(error => {
console.error(error.message);
})
.finally(() => {
console.log('Cleanup');
});
// Async/await syntax
async function fetchData() {
try {
const result = await promise;
console.log(result);
return result;
} catch (error) {
console.error(error.message);
throw error;
} finally {
console.log('Cleanup');
}
}
// Promise.all - all must succeed
const results = await Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
// Promise.allSettled - get all results regardless
const outcomes = await Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts')
]);
outcomes.forEach(outcome => {
if (outcome.status === 'fulfilled') {
console.log(outcome.value);
} else {
console.log(outcome.reason);
}
});
// Promise.race - first to settle
const fastest = await Promise.race([
fetch('/api/primary'),
fetch('/api/backup')
]);
// Promise.any - first to succeed
const firstSuccess = await Promise.any([
fetch('/api/server1'),
fetch('/api/server2')
]);
Examples
// Sequential async operations
async function processItems(items) {
const results = [];
for (const item of items) {
const result = await processItem(item);
results.push(result);
}
return results;
}
// Parallel async operations
async function processItemsParallel(items) {
const promises = items.map(item => processItem(item));
return Promise.all(promises);
}
// Retry pattern
async function fetchWithRetry(url, retries = 3, delay = 1000) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url);
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(r => setTimeout(r, delay * Math.pow(2, i)));
}
}
}
// Timeout pattern
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), ms);
});
return Promise.race([promise, timeout]);
}
const result = await withTimeout(fetch('/api/slow'), 5000);
// Promisify callback-based function
const readFileAsync = (path) => {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf8', (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
};
// Async iteration
async function* asyncGenerator() {
for (let i = 0; i < 5; i++) {
await new Promise(r => setTimeout(r, 100));
yield i;
}
}
for await (const value of asyncGenerator()) {
console.log(value);
}
Fetch API
Key Concepts
- Fetch: Modern API for making HTTP requests
- Request/Response: Objects representing HTTP request/response
- Headers: HTTP headers management
- AbortController: Cancel ongoing requests
- CORS: Cross-Origin Resource Sharing considerations
Common Patterns
// Basic GET request
const response = await fetch('https://api.example.com/data');
const data = await response.json();
// POST request
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
body: JSON.stringify({
name: 'Alice',
email: 'alice@example.com'
})
});
// Other HTTP methods
const response = await fetch(url, { method: 'PUT', body, headers });
const response = await fetch(url, { method: 'PATCH', body, headers });
const response = await fetch(url, { method: 'DELETE' });
// Check response status
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Response methods
const json = await response.json(); // Parse JSON
const text = await response.text(); // Get text
const blob = await response.blob(); // Get binary data
const buffer = await response.arrayBuffer();
const formData = await response.formData();
// Headers
const response = await fetch(url);
response.headers.get('Content-Type');
response.headers.has('Authorization');
// FormData upload
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('name', 'document');
const response = await fetch('/upload', {
method: 'POST',
body: formData // Content-Type set automatically
});
// URL search params
const params = new URLSearchParams({
page: 1,
limit: 10,
search: 'query'
});
const response = await fetch(`/api/items?${params}`);
// Abort request
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, {
signal: controller.signal
});
Examples
// Comprehensive fetch wrapper
async function apiRequest(endpoint, options = {}) {
const baseUrl = 'https://api.example.com';
const defaultHeaders = {
'Content-Type': 'application/json'
};
const config = {
...options,
headers: {
...defaultHeaders,
...options.headers
}
};
if (config.body && typeof config.body === 'object') {
config.body = JSON.stringify(config.body);
}
try {
const response = await fetch(`${baseUrl}${endpoint}`, config);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(error.message || `HTTP ${response.status}`);
}
const contentType = response.headers.get('Content-Type');
if (contentType?.includes('application/json')) {
return response.json();
}
return response.text();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request aborted');
}
throw error;
}
}
// Usage
const users = await apiRequest('/users');
const newUser = await apiRequest('/users', {
method: 'POST',
body: { name: 'Alice' }
});
// Parallel requests
async function fetchDashboardData() {
const [users, posts, stats] = await Promise.all([
apiRequest('/users'),
apiRequest('/posts'),
apiRequest('/stats')
]);
return { users, posts, stats };
}
// Download file
async function downloadFile(url, filename) {
const response = await fetch(url);
const blob = await response.blob();
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
URL.revokeObjectURL(link.href);
}
// Upload with progress (using XMLHttpRequest)
function uploadWithProgress(url, file, onProgress) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) {
onProgress((e.loaded / e.total) * 100);
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`Upload failed: ${xhr.status}`));
}
});
xhr.addEventListener('error', () => reject(new Error('Upload failed')));
const formData = new FormData();
formData.append('file', file);
xhr.open('POST', url);
xhr.send(formData);
});
}
JSON Operations
Key Concepts
- JSON.parse(): Convert JSON string to JavaScript object
- JSON.stringify(): Convert JavaScript object to JSON string
- Reviver/Replacer: Custom transformation during parse/stringify
- Circular references: Must be handled specially
- JSON limitations: No functions, undefined, symbols, or circular refs
Common Patterns
// Basic parsing
const jsonString = '{"name":"Alice","age":30}';
const obj = JSON.parse(jsonString);
// Basic stringify
const obj = { name: 'Alice', age: 30 };
const json = JSON.stringify(obj);
// Pretty print
const pretty = JSON.stringify(obj, null, 2);
// Replacer function (filter/transform)
const json = JSON.stringify(obj, (key, value) => {
if (key === 'password') return undefined; // Exclude
if (typeof value === 'string') return value.toUpperCase();
return value;
});
// Replacer array (whitelist)
const json = JSON.stringify(obj, ['name', 'email']);
// Reviver function (transform on parse)
const obj = JSON.parse(jsonString, (key, value) => {
if (key === 'date') return new Date(value);
return value;
});
// Deep clone — prefer structuredClone(); the JSON round-trip
// works for simple objects only (drops Dates, Maps, undefined)
const clone = structuredClone(original);
// Handle errors
try {
const obj = JSON.parse(invalidJson);
} catch (error) {
if (error instanceof SyntaxError) {
console.error('Invalid JSON:', error.message);
}
}
// Check if valid JSON
function isValidJSON(str) {
try {
JSON.parse(str);
return true;
} catch {
return false;
}
}
Examples
// Handling dates
const data = {
name: 'Event',
date: new Date('2024-01-15')
};
// Dates become strings
const json = JSON.stringify(data);
// '{"name":"Event","date":"2024-01-15T00:00:00.000Z"}'
// Parse with date revival
const parsed = JSON.parse(json, (key, value) => {
const datePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
if (typeof value === 'string' && datePattern.test(value)) {
return new Date(value);
}
return value;
});
// Custom toJSON method
class User {
constructor(name, password) {
this.name = name;
this.password = password;
}
toJSON() {
return {
name: this.name
// Password excluded
};
}
}
const user = new User('Alice', 'secret');
JSON.stringify(user); // '{"name":"Alice"}'
// Handle circular references
function safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value)) {
return '[Circular]';
}
seen.add(value);
}
return value;
});
}
// Local storage helpers
const storage = {
get(key) {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
},
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
remove(key) {
localStorage.removeItem(key);
}
};
storage.set('user', { name: 'Alice', preferences: { theme: 'dark' } });
const user = storage.get('user');
Common Array Methods
Key Concepts
- Transformation methods: Create new arrays (map, filter, slice)
- Aggregation methods: Reduce to single value (reduce, find, some)
- Mutation methods: Modify original array (push, pop, sort, splice)
- Iteration methods: Loop through elements (forEach, for...of)
- Method chaining: Combine multiple methods for complex operations
Common Patterns
const numbers = [1, 2, 3, 4, 5];
// map - transform each element
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10]
// filter - keep matching elements
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4]
// reduce - accumulate to single value
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 15
// forEach - iterate without return
numbers.forEach((n, index) => {
console.log(`Index ${index}: ${n}`);
});
// find - first matching element
const found = numbers.find(n => n > 3);
// 4
// findIndex - index of first match
const index = numbers.findIndex(n => n > 3);
// 3
// some - at least one matches
const hasEven = numbers.some(n => n % 2 === 0);
// true
// every - all match
const allPositive = numbers.every(n => n > 0);
// true
// includes - check existence
const hasThree = numbers.includes(3);
// true
// indexOf/lastIndexOf
const idx = numbers.indexOf(3);
// 2
// slice - copy portion (non-mutating)
const portion = numbers.slice(1, 4);
// [2, 3, 4]
// concat - merge arrays
const merged = numbers.concat([6, 7, 8]);
// flat - flatten nested arrays
const nested = [[1, 2], [3, 4]];
const flat = nested.flat();
// [1, 2, 3, 4]
// flatMap - map then flatten
const result = numbers.flatMap(n => [n, n * 2]);
// [1, 2, 2, 4, 3, 6, 4, 8, 5, 10]
// Array.from - create from iterable
const arr = Array.from('hello');
// ['h', 'e', 'l', 'l', 'o']
// Array.from with map
const squares = Array.from({ length: 5 }, (_, i) => i * i);
// [0, 1, 4, 9, 16]
// Mutating methods (use with caution)
numbers.push(6); // Add to end
numbers.pop(); // Remove from end
numbers.unshift(0); // Add to start
numbers.shift(); // Remove from start
numbers.splice(2, 1); // Remove at index
numbers.sort((a, b) => a - b); // Sort
numbers.reverse(); // Reverse
Examples
// Method chaining
const users = [
{ name: 'Alice', age: 30, active: true },
{ name: 'Bob', age: 25, active: false },
{ name: 'Charlie', age: 35, active: true },
{ name: 'Diana', age: 28, active: true }
];
const result = users
.filter(user => user.active)
.map(user => user.name)
.sort()
.join(', ');
// 'Alice, Charlie, Diana'
// Reduce for complex transformations
const grouped = users.reduce((acc, user) => {
const key = user.active ? 'active' : 'inactive';
if (!acc[key]) acc[key] = [];
acc[key].push(user);
return acc;
}, {});
// Count occurrences
const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'];
const counts = words.reduce((acc, word) => {
acc[word] = (acc[word] || 0) + 1;
return acc;
}, {});
// { apple: 3, banana: 2, cherry: 1 }
// Unique values
const unique = [...new Set(words)];
// ['apple', 'banana', 'cherry']
// Find max/min
const ages = users.map(u => u.age);
const maxAge = Math.max(...ages);
const minAge = Math.min(...ages);
// Partition array
const partition = (arr, predicate) => {
return arr.reduce(([pass, fail], item) => {
return predicate(item)
? [[...pass, item], fail]
: [pass, [...fail, item]];
}, [[], []]);
};
const [active, inactive] = partition(users, u => u.active);
// Sort by multiple criteria
users.sort((a, b) => {
if (a.active !== b.active) {
return b.active - a.active; // Active first
}
return a.name.localeCompare(b.name); // Then by name
});
// toSorted, toReversed, toSpliced (non-mutating, ES2023)
const sorted = numbers.toSorted((a, b) => b - a);
const reversed = numbers.toReversed();
const spliced = numbers.toSpliced(2, 1, 99);
Error Handling
Key Concepts
- try/catch/finally: Handle synchronous errors
- Error types: Error, TypeError, ReferenceError, SyntaxError, etc.
- Custom errors: Extend Error class for specific error types
- Error propagation: Errors bubble up unless caught
- Async error handling: Use try/catch with async/await
Common Patterns
// Basic try/catch
try {
const result = riskyOperation();
console.log(result);
} catch (error) {
console.error('Error:', error.message);
} finally {
cleanup();
}
// Throwing errors
function divide(a, b) {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
// Error types
throw new Error('Generic error');
throw new TypeError('Expected a string');
throw new RangeError('Value out of range');
throw new ReferenceError('Variable not defined');
// Check error type
try {
JSON.parse(invalidJson);
} catch (error) {
if (error instanceof SyntaxError) {
console.error('Invalid JSON');
} else {
throw error; // Re-throw unexpected errors
}
}
// Custom error class
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.name = 'ValidationError';
this.field = field;
}
}
throw new ValidationError('Email is required', 'email');
// Async error handling
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Fetch failed:', error.message);
throw error; // Re-throw for caller to handle
}
}
// Promise error handling
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
// Error boundaries pattern
async function withErrorHandling(fn, fallback) {
try {
return await fn();
} catch (error) {
console.error(error);
return fallback;
}
}
const data = await withErrorHandling(
() => fetchData(),
{ error: true, data: [] }
);
Examples
// Comprehensive error handling
class AppError extends Error {
constructor(message, statusCode = 500, isOperational = true) {
super(message);
this.name = this.constructor.name;
this.statusCode = statusCode;
this.isOperational = isOperational;
Error.captureStackTrace(this, this.constructor);
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} not found`, 404);
}
}
class ValidationError extends AppError {
constructor(errors) {
super('Validation failed', 400);
this.errors = errors;
}
}
// Usage in API
async function getUser(id) {
const user = await db.findUser(id);
if (!user) {
throw new NotFoundError('User');
}
return user;
}
// Global error handler
function handleError(error) {
if (error instanceof ValidationError) {
console.error('Validation:', error.errors);
return { status: 400, errors: error.errors };
}
if (error instanceof NotFoundError) {
console.error('Not found:', error.message);
return { status: 404, message: error.message };
}
// Unexpected error
console.error('Unexpected error:', error);
return { status: 500, message: 'Internal server error' };
}
// Async operation with multiple error types
async function processOrder(orderId) {
let order;
try {
order = await getOrder(orderId);
validateOrder(order);
await chargePayment(order);
await shipOrder(order);
return { success: true };
} catch (error) {
if (error.name === 'PaymentError') {
await refundPayment(order);
}
throw error;
}
}
// Error logging utility
function logError(error, context = {}) {
const errorLog = {
timestamp: new Date().toISOString(),
name: error.name,
message: error.message,
stack: error.stack,
...context
};
console.error(JSON.stringify(errorLog, null, 2));
// Send to error tracking service
}
// Assert utility
function assert(condition, message) {
if (!condition) {
throw new Error(message || 'Assertion failed');
}
}
assert(user.age >= 18, 'User must be at least 18 years old');
Quick Reference
| Category | Method/Syntax | Description |
|---|---|---|
| Variables | let x = 1 |
Block-scoped, reassignable |
const x = 1 |
Block-scoped, constant | |
var x = 1 |
Function-scoped (legacy) | |
| Functions | function fn() {} |
Function declaration |
const fn = () => {} |
Arrow function | |
async function fn() {} |
Async function | |
| Arrays | arr.map(fn) |
Transform elements |
arr.filter(fn) |
Filter elements | |
arr.reduce(fn, init) |
Reduce to value | |
arr.find(fn) |
Find first match | |
arr.forEach(fn) |
Iterate elements | |
[...arr] |
Spread/copy array | |
| Objects | {...obj} |
Spread/copy object |
{a, b} = obj |
Destructure object | |
Object.keys(obj) |
Get keys array | |
Object.values(obj) |
Get values array | |
obj?.prop |
Optional chaining | |
a ?? b |
Nullish coalescing | |
| DOM | querySelector(sel) |
Select element |
querySelectorAll(sel) |
Select all matching | |
createElement(tag) |
Create element | |
addEventListener(evt, fn) |
Add event listener | |
classList.add/remove/toggle |
Modify classes | |
| Promises | new Promise((res, rej) => {}) |
Create promise |
await promise |
Wait for promise | |
Promise.all([...]) |
Wait for all | |
Promise.race([...]) |
First to settle | |
| Fetch | fetch(url) |
GET request |
response.json() |
Parse JSON response | |
fetch(url, {method: 'POST'}) |
POST request | |
| JSON | JSON.parse(str) |
Parse JSON string |
JSON.stringify(obj) |
Convert to JSON | |
| Errors | try {...} catch (e) {...} |
Error handling |
throw new Error(msg) |
Throw error |
Common Issues and Solutions
Issue: undefined is not a function
Cause: Calling something that isn't a function or method doesn't exist.
// Problem
const obj = {};
obj.method(); // TypeError
// Solution: Check existence
if (typeof obj.method === 'function') {
obj.method();
}
// Or use optional chaining
obj.method?.();
Issue: Callback hell / Pyramid of doom
Cause: Nested callbacks make code hard to read and maintain.
// Problem
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
// Deep nesting
});
});
});
// Solution: Use async/await
async function loadAll() {
const a = await getData();
const b = await getMoreData(a);
const c = await getEvenMoreData(b);
return c;
}
Issue: this is undefined in callback
Cause: Regular functions lose this context in callbacks.
// Problem
const obj = {
value: 42,
getValue: function() {
setTimeout(function() {
console.log(this.value); // undefined
}, 100);
}
};
// Solution 1: Arrow function
const obj = {
value: 42,
getValue: function() {
setTimeout(() => {
console.log(this.value); // 42
}, 100);
}
};
// Solution 2: Bind
setTimeout(function() {
console.log(this.value);
}.bind(this), 100);
Issue: Array/Object mutation causing bugs
Cause: Mutating original data leads to unexpected side effects.
// Problem
const original = [1, 2, 3];
const modified = original;
modified.push(4);
console.log(original); // [1, 2, 3, 4] - mutated!
// Solution: Create copies
const modified = [...original, 4];
const modified = original.concat(4);
// For objects
const newObj = { ...original, newProp: value };
Issue: Race conditions with async code
Cause: Multiple async operations completing in unexpected order.
// Problem
let result;
fetchData1().then(data => result = data);
fetchData2().then(data => result = data);
// Which one wins?
// Solution: Use Promise.all or chain properly
const [data1, data2] = await Promise.all([
fetchData1(),
fetchData2()
]);
Issue: Memory leaks with event listeners
Cause: Not removing event listeners when no longer needed.
// Problem: Listener accumulates
function setup() {
window.addEventListener('resize', handleResize);
}
// Solution: Remove when done
function cleanup() {
window.removeEventListener('resize', handleResize);
}
// Or use AbortController
const controller = new AbortController();
window.addEventListener('resize', handleResize, {
signal: controller.signal
});
// Later
controller.abort(); // Removes all listeners with this signal
Issue: Floating point precision errors
Cause: JavaScript uses IEEE 754 floating point.
// Problem
0.1 + 0.2 === 0.3; // false
0.1 + 0.2; // 0.30000000000000004
// Solution: Use tolerance or integers
Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON; // true
// Or work with integers (cents instead of pounds)
const price = 199; // £1.99 in pence
const display = (price / 100).toFixed(2);
Issue: Unhandled promise rejections
Cause: Promises without catch handlers.
// Problem
async function riskyOperation() {
throw new Error('Failed');
}
riskyOperation(); // Unhandled rejection
// Solution: Always handle rejections
riskyOperation().catch(console.error);
// Or with try/catch
try {
await riskyOperation();
} catch (error) {
console.error(error);
}
// Global handler (last resort)
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
});
Related Topics
To further enhance your JavaScript knowledge, consider exploring these complementary topics:
- TypeScript: Adds static typing to JavaScript for improved tooling and error detection at compile time
- Node.js: Server-side JavaScript runtime for building backend applications and APIs
- React/Vue/Angular: Frontend frameworks for building complex, reactive user interfaces
- Testing (Jest/Mocha): Unit and integration testing frameworks for ensuring code quality
- Webpack/Vite: Module bundlers and build tools for optimising JavaScript applications
- Web APIs: Browser APIs like WebSockets, Service Workers, IndexedDB, and Web Workers for advanced functionality