JavaScript Interview Cheatsheet
Key points from 112 JavaScript concepts in one scannable reference. Click any topic to explore the full interactive explanation.
Scope & Hoisting
Scope Basics: Global, Function & Block →Very High frequency
- Global scope: Variables accessible from anywhere in the code
- Function scope: Variables declared with var inside a function
- Block scope: Variables declared with let/const inside {}
- Inner scopes can access outer scope variables (scope chain)
Variable Hoisting: var vs let vs const →Very High frequency
- All declarations are hoisted to the top of their scope during compilation
- var declarations are hoisted AND initialized with undefined
- let and const declarations are hoisted but NOT initialized
- Accessing let/const before declaration throws ReferenceError (TDZ)
Function Hoisting: Declarations vs Expressions →High frequency
- Function declarations: fully hoisted (name + body)
- Function expressions: follow variable hoisting rules
- var function expressions: hoisted as undefined
- let/const function expressions: TDZ error if called early
Temporal Dead Zone (TDZ) Explained →High frequency
- TDZ = time from scope start to variable declaration
- Variables in TDZ exist but cannot be accessed
- Accessing TDZ variable throws ReferenceError (not undefined)
- typeof behaves differently in TDZ (throws vs returns "undefined")
Lexical Scoping & Scope Chain →High frequency
- Lexical = "where written" not "where called"
- Scope chain: inner scope → outer scope → global
- Variable lookup follows the scope chain until found
- Scope is static - doesn't change based on how function is called
What is a Closure? →Very High frequency
- A closure is created when a function is defined inside another function
- The inner function maintains access to outer scope variables
- Variables are captured by reference, not by value
- Closures exist even without explicit return (all inner functions are closures)
Practical Closure Patterns →High frequency
- Data privacy: closures hide variables from external access
- Function factories: create specialized functions with preset configuration
- State preservation: maintain state in event handlers and callbacks
- Memoization: cache expensive function results
Closures
- A closure is created every time a function is created
- Inner functions have access to outer function variables
- The outer variables are captured by reference, not by value
- Closures enable data privacy and stateful functions
The Infamous Loop Closure Bug →Very High frequency
- var is function-scoped, not block-scoped
- All closures in a var loop share the same variable reference
- By the time callbacks run, the loop has finished (i is final value)
- Fix 1: Use let instead of var (block-scoped, new binding each iteration)
Closures & Memory Management →Medium frequency
- Closures keep outer scope variables alive
- Large objects captured in closures cannot be garbage collected
- Event listeners with closures can hold DOM references
- Remove event listeners when no longer needed
The Module Pattern (IIFE + Closure) →Medium frequency
- IIFE creates a new scope that encapsulates private variables
- Return an object with public methods (closures)
- Private variables are truly private - no external access
- Before ES6 modules, this was the standard pattern
Partial Application & Currying →Medium frequency
- Partial application: fix some arguments, return function for rest
- Currying: f(a,b,c) => f(a)(b)(c)
- Both use closures to remember fixed arguments
- Useful for creating specialized functions
Prototypes & OOP
Prototype Chain Fundamentals →High frequency
- Every object has [[Prototype]] (access via __proto__ or Object.getPrototypeOf)
- __proto__ is the object it inherits from
- .prototype is a property of constructor functions only
- Property lookup walks up the prototype chain
Property Lookup & Shadowing →Medium frequency
- Get: Walk up prototype chain until found or null
- Set: Always creates/updates own property (never modifies prototype)
- Own property shadows inherited property with same name
- hasOwnProperty() checks only own properties
How instanceof Works →Medium frequency
- obj instanceof Constructor checks prototype chain
- Returns true if Constructor.prototype is in obj's chain
- Walks up __proto__ links looking for prototype property
- Does not work across iframes (different realms)
ES6 Classes: Prototype Sugar →High frequency
- class is syntactic sugar over constructor functions and prototypes
- constructor() method becomes the constructor function
- Methods are added to Class.prototype
- static methods become properties on the constructor
Classical Inheritance in JavaScript →Medium frequency
- Subclass.prototype = Object.create(Superclass.prototype)
- Call parent constructor: Superclass.call(this, args)
- Fix constructor property after setting prototype
- ES6 extends handles this automatically
Prototype Pollution Attacks →Medium frequency
- Attacker injects properties via __proto__, constructor, or prototype
- Affected operations: merge, clone, extend, deep assign
- Can affect all objects if Object.prototype is polluted
- Prevention: validate keys, use Object.create(null), freeze
- Every object has a [[Prototype]] (accessible via __proto__ or Object.getPrototypeOf)
- Property lookup walks up the prototype chain
- Functions have a .prototype property used for constructor instances
- Object.create() creates objects with a specific prototype
Class Advanced Features →Medium frequency
- Private fields (#) are truly private — accessing them outside the class throws a SyntaxError
- Static methods and properties belong to the class itself, not instances
- Static initialization blocks (static { }) run once when the class is defined
- Public class fields are declared at the top of the class body without let/const
Event Loop & Async
- JavaScript is single-threaded (one call stack)
- Web APIs handle async operations (setTimeout, fetch, etc.)
- Task Queue (Macrotasks): setTimeout, setInterval, I/O
- Microtask Queue: Promises, queueMicrotask, MutationObserver
The Call Stack Explained →High frequency
- Call stack is LIFO: Last In, First Out
- Functions are pushed when called, popped when return
- Stack overflow occurs with infinite recursion
- Stack traces show the path of execution
How the JS Engine + Web APIs Work →High frequency
- JS Engine: Heap (memory) + Call Stack (execution)
- Web APIs: setTimeout, fetch, DOM, etc. (provided by environment)
- Engine executes code on call stack
- Async operations are handed off to Web APIs
Task Queue: Macrotasks →High frequency
- Macrotasks: setTimeout, setInterval, I/O, UI rendering
- Callbacks queue here when Web APIs complete
- Event loop runs ONE macrotask per iteration
- Macrotasks yield between each other (browser can paint)
Microtask Queue: Promises & queueMicrotask →Very High frequency
- Microtasks: Promises, queueMicrotask, MutationObserver
- Event loop drains ALL microtasks before next macrotask
- Microtasks can queue more microtasks (drained recursively)
- Always execute before next macrotask
One Event Loop Cycle →High frequency
- 1. Execute one macrotask from task queue (if any)
- 2. Drain ALL microtasks (execute until microtask queue empty)
- 3. Render (if needed)
- 4. Repeat
Event Loop Starvation →Medium frequency
- Infinite microtasks prevent macrotasks from running
- Long sync operations block the entire thread
- Use setTimeout(fn, 0) to yield control
- Break heavy work into chunks
- Callbacks (1995): Pass a function to run later - simple but leads to nesting
- Callback Hell (2008): Deep nesting creates unreadable "pyramid of doom"
- Promises (2012): Chainable .then() flattens code, unified error handling
- Generators (2015): Pausable functions, paved the way for async/await
Callback Functions 101 →High frequency
- A callback is a function passed into another function as an argument
- Callbacks can be synchronous (array methods) or asynchronous (setTimeout, events)
- Callbacks allow for non-blocking code execution
- Higher-order functions accept callbacks as parameters
Callback Hell & The Pyramid of Doom →High frequency
- Callback hell occurs with deeply nested asynchronous callbacks
- Code becomes harder to read as indentation increases
- Error handling becomes complex and scattered
- Difficult to coordinate multiple async operations
Creating Promises →High frequency
- new Promise(executor) creates a Promise object
- Executor receives resolve and reject functions
- Call resolve(value) to fulfill the Promise
- Call reject(error) to reject the Promise
Promise Chaining →High frequency
- .then() always returns a new Promise
- Return a value to pass it to the next .then()
- Return a Promise to wait for it before continuing
- Errors skip to the next .catch()
Error Handling with Async/Await →High frequency
- Use try/catch for async error handling
- Rejected Promises become thrown exceptions in await
- catch block receives the rejection reason
- Can mix await and .catch() on same Promise
Parallel Async Operations →High frequency
- await runs sequentially by default
- Use Promise.all() to run operations in parallel
- Start operations before awaiting to run in parallel
- Do NOT use await in a loop for independent operations
AbortController →Medium frequency
- AbortController creates a signal; calling controller.abort() triggers cancellation
- Fetch accepts a signal option — aborting throws an AbortError that must be caught
- AbortSignal.timeout(ms) creates a signal that auto-aborts after a duration
- AbortSignal.any([signal1, signal2]) combines multiple signals — first abort wins
Array Methods
Array Mutation Methods: push, pop, splice, sort →Medium frequency
- Mutating methods change the original array
- push/pop work at end, shift/unshift work at beginning
- splice can add, remove, or replace elements at any position
- sort and reverse rearrange elements in place
Array Iteration: forEach, map, filter, find →Very High frequency
- forEach - executes function for each element, returns undefined
- map - transforms each element, returns new array
- filter - keeps elements passing test, returns new array
- find - returns first element passing test, or undefined
Mastering Array.reduce() →High frequency
- reduce((accumulator, current) => newAccumulator, initialValue)
- Can transform array into any type (number, object, array, etc.)
- Always provide initial value to avoid bugs
- Common patterns: sum, groupBy, flatten, pipe, count
Finding Elements: indexOf, includes, find →Medium frequency
- indexOf/lastIndexOf - search by value, returns index or -1
- includes - search by value, returns boolean
- find/findIndex - search by predicate function
- All use strict equality (===) for comparison
Transforming Arrays: slice, concat, flat, join →Medium frequency
- slice(start, end) - extracts portion, returns new array
- concat(...arrays) - merges arrays, returns new array
- flat(depth) - flattens nested arrays
- flatMap(callback) - map + flat combined
Sorting Arrays Correctly →High frequency
- sort() converts elements to strings by default!
- Comparator: (a, b) => negative if a < b, positive if a > b, 0 if equal
- Numeric sort: arr.sort((a, b) => a - b)
- String sort: use localeCompare for proper Unicode
Immutable Array Patterns (ES2023) →Medium frequency
- Immutable operations return new arrays
- Spread operator [...arr] for shallow copies
- ES2023: toSorted(), toReversed(), toSpliced(), with()
- filter() for removing elements immutably
Modern JavaScript (ES6+)
Destructuring: Objects & Arrays →High frequency
- Object: const {a, b} = obj
- Array: const [x, y] = arr
- Defaults: const {a = 1} = obj
- Rename: const {a: newName} = obj
Spread Operator Patterns →High frequency
- Arrays: [...arr1, ...arr2]
- Objects: {...obj1, ...obj2}
- Calls: fn(...args)
- Shallow copies
Rest Parameters →Medium frequency
- function(...args)
- Must be last parameter
- Real array (unlike arguments)
- Works with arrow functions
Template Literals →Medium frequency
- Interpolation: Hello ${name}
- Multi-line support
- Expression evaluation
- Tagged templates
Optional Chaining (?.) →High frequency
- obj?.property
- obj?.[key]
- func?.()
- Short-circuits on nullish
Nullish Coalescing (??) →High frequency
- a ?? b for null/undefined
- Unlike || (0, "" matter)
- Cannot mix with && ||
- Use when 0/"" valid
Logical Assignment Operators →Low frequency
- x ??= y (nullish)
- x ||= y (falsy)
- x &&= y (truthy)
- Conditional assignment
Symbols →Medium frequency
- Symbol() creates a guaranteed-unique value every time — no two symbols are ever equal
- Symbol.for(key) uses a global registry — same key returns the same symbol across realms
- Well-known symbols (Symbol.iterator, Symbol.toPrimitive, Symbol.hasInstance) customize language behavior
- Symbols as property keys are not enumerable by for...in or Object.keys()
Structured Clone & Deep Copy →High frequency
- Spread (...) and Object.assign create shallow copies — only top-level properties are duplicated
- Nested objects in shallow copies still share references with the original
- JSON.parse(JSON.stringify()) loses undefined, functions, Date objects, Map, Set, and RegExp
- structuredClone() (ES2022) handles nested objects, Date, Map, Set, RegExp, and circular references
Tagged Template Literals →Low frequency
- A tag function receives (strings[], ...values) — strings are the static parts, values are the expressions
- The strings array always has one more element than the values array
- strings.raw gives unprocessed escape sequences (backslashes preserved)
- String.raw is the built-in tag that returns raw strings without processing escapes
Other Topics
- Created in 10 days for Netscape browser (1995)
- Multi-paradigm: supports OOP, functional, and procedural styles
- Dynamic typing: types are checked at runtime, not compile time
- Prototype-based inheritance (not class-based like Java)
How JavaScript Executes Your Code →High frequency
- Code executes top-to-bottom, line-by-line (synchronous by default)
- The engine maintains state: what variables exist, their current values
- Comments are ignored - they are for humans only
- Given the same input, code produces the same output (deterministic)
Values, Variables, and Memory →Medium frequency
- Programs manipulate values: numbers, text, true/false, collections
- Values live in memory (think: boxes in a warehouse)
- Variables are labels that point to memory locations
- Reading a variable retrieves the value; writing changes what it points to
Expressions vs Statements →Medium frequency
- Expressions produce/evaluate to a value
- Statements perform an action (don't produce a value)
- Expressions can nest inside other expressions
- Statements cannot go where expressions are expected
Reading Code Like an Engineer →Medium frequency
- Professional developers spend most time reading existing code
- Start by identifying inputs (parameters) and outputs (return value)
- Find the "happy path" first - the normal successful flow
- Variable and function names are documentation - read them carefully
The Debugging Mindset →High frequency
- Bugs are normal - expect them, don't fear them
- Error messages are clues, not insults - read them carefully
- The debugging cycle: Hypothesis → Test → Learn → Repeat
- Isolate the problem: find the smallest code that reproduces it
- var: function-scoped, can be redeclared, hoisted with undefined
- let: block-scoped, cannot be redeclared, hoisted but in TDZ
- const: block-scoped, cannot be reassigned, must be initialized
- Use const by default, let when you need to reassign
- 7 primitives: string, number, boolean, null, undefined, symbol, bigint
- Objects: everything else (arrays, functions, dates, etc.)
- typeof returns the type as a string
- Primitives are copied by value, objects by reference
- Arithmetic: + - * / % ** (exponentiation)
- Comparison: == (loose) vs === (strict)
- Logical: && (and) || (or) ! (not)
- && returns first falsy or last value, || returns first truthy or last value
- Function declarations are hoisted (can call before definition)
- Function expressions are NOT hoisted
- Arrow functions have shorter syntax and no own "this"
- Functions can return values or undefined by default
- if/else: most common, can chain with else if
- switch: compare one value against many cases
- Ternary: condition ? valueIfTrue : valueIfFalse
- Falsy values: false, 0, "", null, undefined, NaN
- for: when you know how many iterations
- while: when you don't know how many iterations
- for...of: iterate over array VALUES
- for...in: iterate over object KEYS
- Arrays are zero-indexed (first element is at index 0)
- Arrays can hold mixed types
- length property gives the count of elements
- Mutating methods: push, pop, shift, unshift, splice
- Objects store data as key-value pairs (properties)
- Keys are strings (or Symbols), values can be anything
- Dot notation: obj.key vs Bracket notation: obj["key"]
- Objects are passed by reference, not copied
- Variable declarations (var) are hoisted, but not their assignments
- Function declarations are fully hoisted (name + body)
- let and const are hoisted but stay in the "Temporal Dead Zone" until declared
- Function expressions are NOT hoisted like function declarations
- Seven primitives: string, number, boolean, null, undefined, symbol, bigint
- typeof null is "object" (legacy quirk)
- Loose equality (==) coerces types, strict (===) does not
- + concatenates when either operand is a string
- this is determined at call time, not definition time
- Rule 1: new binding - this = new instance
- Rule 2: Explicit binding (call/apply/bind) - this = specified object
- Rule 3: Implicit binding (obj.method()) - this = object left of dot
- A recursive function calls itself with a smaller/simpler input
- Every recursion needs a BASE CASE to stop (or you get infinite recursion)
- The call stack grows with each recursive call, then unwinds as functions return
- Recursion can be converted to iteration (and vice versa)
- Stack: stores primitives (numbers, booleans, strings) and function call frames
- Heap: stores objects, arrays, and functions (dynamic allocation)
- Variables hold references (pointers) to heap objects, not the objects themselves
- Garbage Collection: V8 uses mark-and-sweep to free unreachable objects
- Parser converts source code to Abstract Syntax Tree (AST)
- Ignition: interpreter that generates bytecode for fast startup
- TurboFan: JIT compiler that optimizes "hot" frequently-run code
- Hidden Classes: V8 creates shapes for objects to optimize property access
- Node.js event loop has 6 phases (not just micro/macro queues)
- Timers phase: executes setTimeout/setInterval callbacks
- Poll phase: retrieves new I/O events, executes I/O callbacks
- Check phase: executes setImmediate callbacks
- Streams process data in chunks (memory efficient)
- Four types: Readable, Writable, Duplex, Transform
- Buffers are fixed-size chunks of binary data
- Backpressure: slow consumer signals fast producer to pause
- HTML parsing builds the DOM (Document Object Model)
- CSS parsing builds the CSSOM (CSS Object Model)
- DOM + CSSOM = Render Tree (only visible elements)
- Layout: calculates exact position and size of each element
- Workers run in separate threads (true parallelism)
- Main thread stays responsive during heavy computation
- Communication via postMessage (data is copied, not shared)
- Workers have no DOM access (no document, window, etc.)
- Static HTML (1990s): Simple but no interactivity
- CGI/PHP Era: Dynamic content but full page reloads
- AJAX (2005): Partial updates without reload, but complex state
- SPA Era (2010s): App-like UX but poor SEO & slow initial load
- Global Scripts (1995): No modules, everything global, order-dependent
- IIFE Pattern (2009): Closures for encapsulation, still manual ordering
- CommonJS (2009): Node.js require/exports, synchronous, server-focused
- AMD (2011): Async loading for browsers, verbose callback syntax
- jQuery DOM (2006): State lived in the DOM, read/write directly
- MVC/Backbone (2010): Separated models from views, event-driven
- Two-Way Binding (2012): Angular 1.x magic, but hard to debug
- Flux (2014): Unidirectional flow, actions → dispatcher → store
- No Build (1995): Script tags, manual ordering, FTP deploy
- Task Runners (2012): Grunt/Gulp automated concatenation and minification
- Module Bundlers (2014): Webpack enabled import/export in browsers
- Zero-Config (2017): CRA/Parcel hid complexity but were still slow
Error-First Callback Pattern (Node.js) →Medium frequency
- First parameter is always an error object (or null if no error)
- Second parameter contains the successful result
- Standard pattern in Node.js core modules (fs, http, etc.)
- Always check if error exists before using result
- A Promise represents a value that may be available now, later, or never
- Promise states: pending → fulfilled OR rejected (immutable once settled)
- Promise.all() fails fast: rejects on first rejection
- Promise.race() returns first settled (fulfilled OR rejected)
Consumsuming Promises: then, catch, finally →High frequency
- .then(onFulfilled, onRejected) handles success and optionally error
- .catch(onRejected) is shorthand for .then(null, onRejected)
- .finally(onFinally) runs on both success and failure
- These methods return new Promises (enabling chaining)
Promise.all, race, allSettled, any →High frequency
- Promise.all([promises]) - waits for all, fails on first rejection
- Promise.race([promises]) - returns first to settle (fulfilled OR rejected)
- Promise.allSettled([promises]) - waits for all, never rejects
- Promise.any([promises]) - returns first fulfilled, ignores rejections until all fail
Async/Await Syntax Basics →High frequency
- async function always returns a Promise
- await pauses execution until Promise settles
- await can only be used inside async functions
- Top-level await available in ES2022 (modules)
- Currying transforms f(a, b, c) into f(a)(b)(c) - one arg at a time
- Partial application fixes some arguments, returns function for the rest
- pipe() flows left-to-right: pipe(f, g, h)(x) = h(g(f(x)))
- compose() flows right-to-left: compose(f, g, h)(x) = f(g(h(x)))
- Debounce: waits for pause in calls before executing (e.g., search input)
- Throttle: executes at most once per interval (e.g., scroll handler)
- Both use closures to persist timer state between calls
- Leading edge: execute immediately on first call
- Memoization trades memory for speed - cache results for repeated calls
- Works best for pure functions (same input → same output)
- Cache key is typically derived from function arguments
- memoizeOne: caches only the last result (great for React)
Try, Catch, Finally →High frequency
- try: code that might throw
- catch: handles errors
- finally: always runs
- Error object properties
Native Error Types →Medium frequency
- Error: base type
- TypeError: wrong type
- ReferenceError: undefined var
- SyntaxError: invalid code
Creating Custom Errors →Medium frequency
- Extend Error class
- Set name property
- Capture stack trace
- Custom properties
Implicit Type Coercion →High frequency
- Arithmetic converts to numbers
- String + anything = string
- == coerces, === does not
- Logical ops return values
Notorious Coercion Edge Cases →Medium frequency
- [] + [] = ""
- [] + {} = "[object Object]"
- typeof null = "object"
- NaN !== NaN
Strings & String Methods →High frequency
- Strings are immutable — methods always return new strings
- JS auto-boxes string primitives to String objects for method access
- charAt(i) and bracket notation str[i] access individual characters
- slice(start, end) extracts substrings (supports negative indices)
Equality Comparisons →Very High frequency
- === (strict) compares without type coercion — prefer this by default
- == (loose) performs type coercion before comparing, following complex rules
- Object.is() is like === but handles NaN and +0/-0 correctly
- NaN === NaN is false — use Object.is(NaN, NaN) or Number.isNaN()
JSON →High frequency
- JSON.parse(string) converts a JSON string into a JavaScript value
- JSON.stringify(value) converts a JavaScript value into a JSON string
- JSON cannot represent: functions, undefined, Symbol, circular references
- replacer parameter in stringify controls which properties are included
for...in vs for...of →High frequency
- for...in iterates over enumerable property keys (strings), including inherited ones
- for...of iterates over iterable values (arrays, strings, maps, sets)
- for...in on arrays gives string indices, not values — avoid this
- for...in includes inherited properties — use hasOwnProperty to guard
typeof & Type Checking →High frequency
- typeof returns a string: "string", "number", "boolean", "undefined", "object", "function", "symbol", "bigint"
- typeof null === "object" is a famous bug that can never be fixed
- typeof for undeclared variables returns "undefined" (does not throw)
- Array.isArray() is the only reliable way to check for arrays
Short-Circuit Evaluation →Medium frequency
- && returns the first falsy value, or the last value if all are truthy
- || returns the first truthy value, or the last value if all are falsy
- Both operators return actual values, not necessarily booleans
- Falsy values: false, 0, "", null, undefined, NaN (6 total)
Map & Set →High frequency
- Map keys can be any type (objects, functions, primitives) unlike object keys which are always strings/symbols
- Map preserves insertion order and has a .size property
- Set stores only unique values with O(1) add/has/delete
- Both Map and Set are iterable with for...of, forEach, and spread
WeakMap & WeakSet →Medium frequency
- WeakMap keys and WeakSet values must be objects — no primitives
- Entries are automatically garbage-collected when the key object has no other references
- Not iterable — no for...of, no .keys(), no .values(), no .entries()
- No .size property — the runtime cannot know the count since entries may be GC'd at any time
Getters, Setters & Property Descriptors →Medium frequency
- get/set syntax creates accessor properties that run code on read/write
- Object.defineProperty controls writable, enumerable, and configurable flags
- Data descriptors have value/writable; accessor descriptors have get/set — mutually exclusive
- Object.getOwnPropertyDescriptor reveals the full descriptor of any property
Object Static Methods →High frequency
- Object.keys/values/entries return arrays of own enumerable string-keyed properties
- Object.assign performs shallow copy — nested objects are still shared by reference
- Object.freeze makes an object immutable (shallow) — nested objects are NOT frozen
- Object.seal prevents adding/deleting properties but allows modifying existing values
Strict Mode →Medium frequency
- "use strict" at the top of a script or function body enables strict mode
- ES modules and class bodies are always in strict mode — no directive needed
- Standalone function this is undefined instead of the global object
- Assigning to undeclared variables throws ReferenceError instead of creating globals
Higher-Order Functions →High frequency
- A HOF takes a function as an argument or returns a function (or both)
- Function factories create specialized functions from general ones using closures
- The middleware pattern chains HOFs where each can modify input, output, or control flow
- Decorators wrap a function to add behavior without modifying the original
Iterators & Generators →Medium frequency
- An iterator is an object with a next() method that returns { value, done }
- An iterable is an object with a [Symbol.iterator]() method returning an iterator
- Generator functions (function*) pause at each yield and resume when next() is called
- Generators are lazy — they compute values on demand, not all at once
Regular Expressions →Medium frequency
- Two creation forms: /pattern/flags literal and new RegExp("pattern", "flags")
- Flags: g (global), i (case-insensitive), m (multiline), s (dotAll), u (unicode)
- Character classes: \d (digit), \w (word), \s (whitespace), . (any char)
- Quantifiers: + (1+), * (0+), ? (0-1), {n,m} (range)
Proxy & Reflect →Medium frequency
- Proxy wraps a target object with a handler containing traps for operations
- Common traps: get, set, has, deleteProperty, apply, construct
- Reflect mirrors every Proxy trap and provides the default operation behavior
- Always use Reflect inside traps to forward to the default behavior
Async Iterators →Low frequency
- Symbol.asyncIterator defines the async iteration protocol on objects
- Async generators (async function*) combine generators with async/await
- for-await-of loop consumes async iterables, awaiting each yielded promise
- Each next() call returns a Promise<{ value, done }>
DOM Events & Event Delegation →Very High frequency
- addEventListener(type, handler, options) attaches event listeners to DOM nodes
- Events propagate in 3 phases: capture (down), target, bubble (up)
- event.target is the element that fired; event.currentTarget is the listener element
- Event delegation: one parent listener handles events for all children via event.target
Fetch API →High frequency
- fetch() returns a Promise<Response> — does NOT reject on HTTP errors (404, 500)
- Always check response.ok or response.status before parsing the body
- Body parsing methods: json(), text(), blob(), arrayBuffer(), formData()
- Request options: method, headers, body, mode, credentials, signal
Web Storage →Medium frequency
- localStorage persists across sessions; sessionStorage clears when the tab closes
- Both store strings only: use JSON.stringify/JSON.parse for objects and arrays
- API: setItem(key, value), getItem(key), removeItem(key), clear(), key(index)
- Storage limit is roughly 5MB per origin (varies by browser)