JavaScript uses automatic memory management with a garbage collector, typically the Mark-and-Sweep algorithm. It allocates memory for objects and variables and frees it when they are no longer reachable. The garbage collector identifies unreachable objects by marking live objects from roots (e.g., global object) and sweeping unmarked ones. Example:
let obj = { data: 'test' };
obj = null; // obj is now eligible for garbage collection
JavaScriptIIFEScope
IIFEs are functions defined and executed immediately, often used to create a private scope and avoid polluting the global namespace. They are wrapped in parentheses and invoked with (). Example:
Prototypal inheritance allows objects to inherit properties and methods from other objects via their prototype. Each object has a [[Prototype]] link, accessed via __proto__ or Object.getPrototypeOf. When a property is accessed, JavaScript looks up the prototype chain until it finds the property or reaches null. Example:
A shallow copy duplicates only the top-level properties of an object, with nested objects still referencing the original. A deep copy duplicates all levels, creating fully independent copies. Shallow copy can be done with Object.assign or spread operator; deep copy requires structuredClone or custom logic. Example:
The event loop enables asynchronous execution in JavaScript’s single-threaded model. It processes the call stack, then checks the task queue (macrotasks like setTimeout) and microtask queue (promises). Microtasks run before the next macrotask, ensuring non-blocking behavior. Example:
JavaScript modules (ES Modules) allow code to be split into reusable files. Use export to expose variables, functions, or classes, and import to use them in other modules. Modules are executed in strict mode and have their own scope. Example:
Microtasks (e.g., Promise.then, queueMicrotask) are high-priority tasks executed immediately after the current call stack clears. Macrotasks (e.g., setTimeout, setInterval, DOM events) are lower-priority, executed in the next event loop iteration. Microtasks can delay macrotasks. Example:
A promise chain is a sequence of .then() or .catch() calls on a promise, allowing sequential asynchronous operations. Each .then() returns a new promise, enabling chaining. Errors are caught by the nearest .catch(). Example:
Promise.resolve(1)
.then(x => x * 2)
.then(x => x + 1)
.then(result => console.log(result)) // 3
.catch(err => console.log(err));
JavaScriptDebouncingThrottlingPerformance
Debouncing delays a function’s execution until after a specified time since the last call, useful for events like input typing. Throttling limits execution to once every specified interval, ideal for events like scrolling. Example:
function debounce(fn, delay) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
const log = debounce(() => console.log('Debounced'), 1000);
log(); log(); // Logs once after 1s
JavaScriptasync/awaitAsynchronous Programming
async/await is syntactic sugar over promises. An async function returns a promise, and await pauses execution until the promise resolves, using the event loop to handle concurrency. Internally, it uses generators and promise resolution. Example:
async function fetchData() {
const data = await new Promise(resolve => setTimeout(() => resolve('Data'), 1000));
console.log(data); // Data
}
fetchData();
JavaScriptCall StackExecution Context
The call stack is a LIFO (Last In, First Out) structure tracking function execution in JavaScript. Each function call adds a frame to the stack; when it returns, the frame is popped. Stack overflow occurs if the stack grows too large (e.g., infinite recursion). Example:
function a() { b(); }
function b() { console.log('b'); }
a(); // Call stack: a -> b -> (pop b) -> (pop a)
JavaScriptService WorkersWeb APIs
Service workers are JavaScript scripts running in the background, enabling offline capabilities, push notifications, and caching for Progressive Web Apps. They intercept network requests and manage cache with the Cache API. Example:
WeakMap and WeakSet are collections that hold weak references to objects, allowing garbage collection if no other references exist. WeakMap keys are objects, and WeakSet values are objects. They are non-iterable and used for memory management. Example:
let obj = {};
const weakMap = new WeakMap();
weakMap.set(obj, 'data');
console.log(weakMap.get(obj)); // data
obj = null; // obj is eligible for garbage collection
JavaScriptGeneratorsIterators
Generators are functions that can pause and resume execution using yield, returning an iterator. They are defined with function* and used for lazy evaluation or asynchronous flows. Example:
Implement a deep clone by recursively copying all nested objects, handling arrays, dates, and circular references. Alternatively, use structuredClone() for modern browsers. Example:
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
const clone = Array.isArray(obj) ? [] : {};
seen.set(obj, clone);
for (let key in obj) clone[key] = deepClone(obj[key], seen);
return clone;
}
const obj = { a: 1, b: { c: 2 } };
const cloned = deepClone(obj);
obj.b.c = 3;
console.log(cloned.b.c); // 2
JavaScriptFunction CurryingFunctional Programming
Currying transforms a function with multiple arguments into a sequence of single-argument functions. It’s useful for partial application, creating reusable function templates, and functional programming. Example:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn(...args);
return (...nextArgs) => curried(...args, ...nextArgs);
};
}
const add = curry((a, b) => a + b);
console.log(add(2)(3)); // 5
console.log(add(2, 3)); // 5
JavaScriptMemory LeaksPerformance
Prevent memory leaks by removing event listeners, clearing timers, nullifying references, using WeakMap/WeakSet, and avoiding global variables. Profile with browser dev tools to identify leaks. Example:
Common ES6+ features include arrow functions, let/const, destructuring, spread/rest operators, template literals, promises, async/await, modules, default parameters, and classes. Example:
.call() invokes a function with a specified this and individual arguments. .apply() is similar but takes arguments as an array. .bind() creates a new function with a fixed this and optional pre-set arguments, without invoking immediately. Example:
function greet(greeting) { return `${greeting}, ${this.name}`; }
const obj = { name: 'Alice' };
console.log(greet.call(obj, 'Hello')); // Hello, Alice
console.log(greet.apply(obj, ['Hi'])); // Hi, Alice
const bound = greet.bind(obj, 'Hey');
console.log(bound()); // Hey, Alice
JavaScriptMemoizationPerformance
Memoization caches a function’s results for given inputs to avoid redundant computation. Implement it with a cache (e.g., object or Map) to store input-output pairs. Example:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const slowFn = x => x * 2;
const memoized = memoize(slowFn);
console.log(memoized(5)); // 10
console.log(memoized(5)); // 10 (cached)
JavaScriptPolyfillsCompatibility
Polyfills are scripts that provide modern JavaScript features in older browsers that lack support. They implement missing APIs like Promise or Array.includes. Example:
A Proxy wraps an object to intercept and customize operations like property access or assignment. It uses a handler with traps (e.g., get, set) for custom behavior, useful for validation or logging. Example:
Handle promise errors with .catch() or try/catch in async/await. Ensure all promises in a chain have a .catch() to avoid unhandled rejections. Use try/catch for async functions to manage errors cleanly. Example:
async function fetchData() {
try {
const data = await new Promise((_, reject) => setTimeout(() => reject('Error'), 1000));
console.log(data);
} catch (err) {
console.log(err); // Error
}
}
fetchData();
JavaScriptSymbolsES6
Symbols are unique, immutable primitives introduced in ES6, often used as object property keys to avoid naming collisions. They are created with Symbol() and can have optional descriptions. Example:
Tail call optimization (TCO) allows recursive functions to reuse the same stack frame for tail calls, preventing stack overflow. JavaScript supports TCO in strict mode, but not all engines implement it reliably. Example:
function factorial(n, acc = 1) {
'use strict';
if (n <= 1) return acc;
return factorial(n - 1, n * acc); // Tail call
}
console.log(factorial(5)); // 120
JavaScriptPerformance OptimizationBrowser
Optimize JavaScript by minimizing DOM operations, using requestAnimationFrame for animations, debouncing/throttling event handlers, avoiding memory leaks, and leveraging lazy loading. Use performance.now() for profiling and bundle with tools like Webpack. Example:
Object.defineProperty defines or modifies a property on an object, allowing control over its value, writability, enumerability, and configurability. It’s used for fine-grained property management. Example:
Handle circular dependencies by restructuring code to avoid them, using lazy evaluation, or deferring imports. Export functions or objects after their dependencies are resolved to prevent undefined references. Example:
// a.js
export let a = () => b();
// b.js
import { a } from './a.js';
export let b = () => console.log('b');
a(); // b (works if exports are resolved)
JavaScriptReactivityFrameworks
Reactivity in frameworks like Vue or React enables automatic UI updates when data changes. It’s implemented with proxies (Vue) or state management (React), tracking dependencies and triggering re-renders when observed data mutates. Example:
Implement a custom iterable by defining a [Symbol.iterator] method that returns an iterator object with a next() method, which yields { value, done } objects. Example:
const myIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
}
return { done: true };
}
};
}
};
for (let x of myIterable) console.log(x); // 1, 2, 3