113 questions
Start with automated conversion, incremental class adoption via codemods, maintain behavior parity with tests, slowly remove Prototype-based APIs, adopt bundler for ESM.
Use performance profiling → pinpoint reflows (excessive DOM updates), deep diff cycles; fix by virtualization (windowing), memoizing list items, using requestAnimationFrame, batching updates, optimizing render functions.
Use Service Workers, IndexedDB, background sync. Version items with timestamps, use CRDT or last-write-wins, resolve conflicts in sync layer, queue operations while offline.
Use window.onerror, window.addEventListener('unhandledrejection'), custom error classes, centralized logging to backend, fallback UI/error boundaries, retry logic, circuit breaker.
Sanitize user input, use CSP, escape dynamic DOM insertion, avoid innerHTML. For objects: deep-freeze, avoid untrusted Object.assign, use Object.create(null) for maps, lock prototypes via Object.freeze(Object.prototype).
Delegate to Web Workers, use TypedArrays or Offload computations to wasm or transferable object, update UI via postMessage, show intermediate progress indicators.
Use schema-driven forms, validate using Constraint Validation API or schema (Yup), debounce validation, lazy load validation rules, isolate form state, render dynamically with virtualized inputs.
Use modular architecture with ES modules or a monorepo approach. Employ:
new, tightly coupled with class semantics.this, more testable.Prefer factory functions in larger apps for better testability and encapsulation unless class inheritance is crucial.
util.promisify) or manually wrap callbacks into Promises.async/await to make the flow readable.React.memo, useMemo)requestAnimationFrame for animationsWeakMap or WeakRef to avoid strong referencesOccurs when long-running tasks (e.g., while loops) block the main thread. Prevent it by:
setTimeout, requestIdleCallback, or Web WorkersObject.assignUse Chrome DevTools → Memory tab → take heap snapshots. Look for:
It happens when removed DOM elements are still referenced in JS (e.g., event handlers not cleaned). Use removeEventListener or WeakRef.
Event loop processes:
Promise.then, MutationObserver) before next macrotasksetTimeout, setInterval) executed after microtasksUse:
setTimeout or requestIdleCallback to chunk taskseval, use strict mode, validate inputsUse centralized state management (e.g., Redux, Zustand), with immutability and selectors. Modularize state slices per feature.
null: Intentional absence of valueundefined: Uninitialized or missing valuevoid 0: Always returns undefined, used to protect against reassigned undefinedUse Webpack 5 Module Federation plugin:
localStorage: Persistent, string-based, 5–10 MBsessionStorage: Per-tab onlyIndexedDB: Structured data, asynchronous, large capacityIn JS, it's often implemented via custom events or EventEmitter.
class Subject {
observers = [];
subscribe(fn) { this.observers.push(fn); }
notify(data) { this.observers.forEach(fn => fn(data)); }
}
They hold weak references, allowing GC of keys when not used elsewhere — ideal for metadata or private data in classes.
JS runs on a single-threaded event loop. Concurrency is simulated using callbacks, promises, and async/await via the event loop.
Use frameworks like Jest/Mocha with done callback, async/await, or return a Promise from the test function.
Caused by uncontrolled recursion or infinite loops. Fix by:
Proxy lets you intercept and define custom behavior for fundamental operations (e.g., get, set). Used for:
A recursive function that returns another function’s result directly can reuse stack. Limited browser support (mostly non-strict mode).
Variable and function declarations are moved to the top of their scope.
var is hoisted and initialized as undefinedlet/const are hoisted but uninitialized (TDZ)It's the phase between entering the scope and variable declaration where accessing a let/const variable throws a ReferenceError.
Symbol.iterator)A closure is a function that retains access to its lexical scope even when the outer function has finished execution.
Real-world uses:
Promise.all cautiouslyUse:
clinic.jsUse Object.defineProperty to define non-enumerable, read-only, or getter/setter-based properties for controlled access.
Service workers are background scripts that intercept network requests for caching and offline support.
Used in:
fetch(url, { credentials: 'include' })Generators (function*) yield values lazily.
Used in:
call: Invokes function with argumentsapply: Same as call but uses arraybind: Returns new function with bound contextIt prevents runtime errors when accessing deep nested objects that might be undefined or null.
user?.address?.city // won't throw if user or address is undefined
Use Map when:
Modules (ESM, CommonJS) allow encapsulated code, reusability, and dependency management, which improves maintainability in large codebases.
setTimeout and setInterval are managed via the Web APIs and queued into the event loop once the delay is complete. They are not precise timers.
react-window)requestAnimationFrameconsole.time, Performance.now()==: Type coercion comparison===: Strict equality
Use === always to avoid unexpected coercion.
structuredClone() (modern)JSON.parse(JSON.stringify(obj)) (limited)lodash.cloneDeepclass EventBus {
events = {};
on(event, fn) { (this.events[event] ||= []).push(fn); }
emit(event, data) { (this.events[event] || []).forEach(fn => fn(data)); }
}
DocumentFragmentIntersectionObserverloading="lazy" for imagesTransforming a function with multiple arguments into a sequence of unary functions.
Used in functional programming and reusability.
const add = x => y => x + y;
Use Chrome DevTools Memory tab to take heap snapshots. Look for detached DOM nodes or retained closures. Check for non-cleaned subscriptions in useEffect, unremoved event listeners, and unreleased intervals/timers. Profile components with React DevTools.
By using the latest ref pattern:
const latestValue = useRef(value);
useEffect(() => {
latestValue.current = value;
}, [value]);Avoid depending on old values in closures by referring to latestValue.current inside callbacks.
Use differential bundling with tools like Vite/Rollup/Webpack + Babel. Serve modern ES modules (type="module") to new browsers and legacy bundles (with nomodule) to older ones.
Code splitting with dynamic import(), tree-shaking unused code, compressing assets (Gzip/Brotli), lazy loading non-critical routes/components, using HTTP/2 for parallel downloads.
Microtasks (Promise.then, queueMicrotask) run before rendering and have higher priority. Macrotasks (setTimeout, setInterval) run after. Improper microtask usage can block rendering.
When you want fine-grained control (e.g., making a property read-only, non-enumerable, or setting custom getter/setter logic), such as enforcing internal encapsulation.
JS might be storing session data in-memory (e.g., a token in a variable or non-persistent storage like sessionStorage). Upon tab refresh or inactivity, it gets lost. Use localStorage with expiration logic or rely on HTTP-only secure cookies.
Use a leading-edge debounce function (e.g., Lodash's _.debounce with { leading: true, trailing: false }).
Never inject raw user content into HTML. Use DOM APIs (textContent), sanitize inputs using libraries (e.g., DOMPurify), and enforce CSP headers on the server.
Service workers enable caching via the Cache API, intercept requests, and serve assets offline or from cache, improving performance and reliability in flaky networks.
this may not refer to the intended context. Solutions include using arrow functions (lexical this), bind(this) in constructors, or class fields in modern JS.
Use DevTools Performance tab: record runtime, look for long tasks, layout thrashing, reflows, expensive paint times, and JS call stacks. Use Lighthouse to audit performance.
Use React.memo to prevent unnecessary re-renders. Profile with React DevTools. Check useEffect dependencies. Avoid inline objects/arrays/functions passed as props.
Batch DOM changes using DocumentFragments or requestAnimationFrame. Avoid layout thrashing. Use transform and opacity for animations (they don’t trigger reflow).
Though ES6 specifies TCO, most modern JS engines (like V8/Chrome) don’t support it due to debugging complexities. TCO allows recursive functions to avoid growing the call stack.
It throws an error on circular references. Use a replacer function or libraries like flatted to handle them gracefully.
Use structured cloning (structuredClone(obj)) or libraries like Lodash _.cloneDeep. Avoid JSON.stringify for complex types (functions, Date, undefined).
Capture stack traces using window.onerror or ErrorBoundary (React). Use console.trace(), source maps, and runtime logs to trace user steps. Automate with Sentry or Bugsnag.
Storing metadata tied to DOM nodes or objects without preventing garbage collection (e.g., memoization caches, internal component state).
forEach doesn’t await async functions. Use for...of with await, or Promise.all() with map() for parallel processing.
Use IntersectionObserver API to detect when the sentinel element is visible and trigger more content loading.
Regularly take heap snapshots, monitor detached DOM nodes, use WeakMap where appropriate, and audit long-held event listeners.
Refactor using async/await, break into reusable async functions, or use Promises with chaining. Consider using RxJS for complex async flows.
Use Module Federation in Webpack 5 with shared singleton dependencies, or external CDNs with careful version pinning and semantic versioning.
It makes the object immutable at the top level. It’s shallow — nested objects can still be modified unless recursively frozen.
eval() executes arbitrary code, introducing XSS vulnerabilities, blocking JS optimizations, and potentially breaking scope chains.
Array.prototype.myFlat = function(depth = 1) {
return this.reduce((acc, val) =>
acc.concat(Array.isArray(val) && depth > 1 ? val.myFlat(depth - 1) : val), []);
};
Use ESLint rules (no-console) in shared config, CI integration to fail builds, and optionally strip logs using Babel plugins or Webpack production mode.
If closures capture variables or DOM nodes that are never released (e.g., through long-lived timers or event listeners), they prevent GC from cleaning up.
Avoid storing in localStorage/sessionStorage for critical secrets. Prefer secure HTTP-only cookies with same-site settings. Always validate on server.
requestAnimationFrame syncs with display refresh (usually 60fps), is more efficient and prevents layout jank. setTimeout is inaccurate due to delay drift.
It means JS is blocking the main thread for too long. Optimize long tasks, break large bundles, use code splitting, and reduce JS execution time.
The TDZ (Temporal Dead Zone) is the time between let/const declaration and initialization. Accessing variables in the TDZ throws a ReferenceError.
Used Proxy to intercept state changes in a data store for validation, auto-saving, or reactivity (like Vue does internally).
Use AbortController to cancel previous fetches. Track request IDs to ignore outdated responses. Use useEffect cleanup in React.
Use context API for shared global data. For more complex apps, use state libraries like Redux, Zustand, Jotai, or even RxJS.
The reconciler compares the virtual DOM trees and figures out the minimum number of DOM changes using keys and heuristics. It works with the renderer (e.g., DOM, native).
For controlled iteration (e.g., pagination), handling async flows via redux-saga, or simulating tasks like polling or streaming.
Use throttling (_.throttle) or track last click timestamp and disable the button temporarily.
A == comparison between 0 and '' evaluated true unexpectedly. Solved by always using === and applying lint rules.
Reduces readability and increases error propagation complexity. Use async/await, flatten control flow, or use error boundaries.
Used Web Workers for heavy data parsing or processing (e.g., CSV to JSON) to avoid UI blocking. Communicated via postMessage.
Part of Web Components. You can define reusable elements using customElements.define. Useful for shared UI across frameworks.
img.onload = () => console.log('Loaded!');
img.onerror = () => console.error('Failed!');
Module boundaries, shared utils, ESLint/Prettier, TypeScript, CI/CD, proper folder structure, API schemas (OpenAPI), performance budgets.
Use requestIdleCallback, or defer with setTimeout(fn, 0), or split bundles and load async via import().
Use Performance API (performance.getEntriesByType('script')) or monitor parse/compile timings via Lighthouse or Chrome DevTools.
Read DOM once, store values in variables, apply writes later. Avoid interleaving reads and writes.
Understand it’s placed in the macrotask queue. The actual execution waits for the call stack to clear and other tasks to finish.
Include API version in URL (/api/v2/...), or use custom headers. Abstract logic in a version-aware API client.
Sign in to join the discussion and post comments.
Sign in