Đi tới nội dung

Câu hỏi phỏng vấn

Câu hỏi phỏng vấn lọc theo vai trò, chủ đề và cấp độ: hơn trăm câu chuyên sâu có lời giải đầy đủ, cùng các câu rút từ bài viết trên blog dẫn về đúng đoạn bài.

304 câu hỏi

  1. Trung cấpJavaScript12 phút đọc

    What are async/await and how do they work?

    Gợi ý trả lời

    Async/await is syntactic sugar built on top of Promises that allows asynchronous code to be written in a synchronous-looking manner. An async function always returns a Promise, and the await keyword pauses execution of the current async function until a Promise settles. Await does not block the JavaScript thread; it simply yields control back to the Event Loop. Under the hood, async/await is transformed into Promise chains. For independent asynchronous operations, Promise.all should be used to execute tasks concurrently and improve performance.

    Đọc lời giải đầy đủ
  2. Cơ bảnJavaScript6 phút đọc

    What is the difference between call, apply, and bind in JavaScript? When would you use each, and how do you implement a custom polyfill for Function.prototype.bind?

    Gợi ý trả lời

    call, apply, and bind are utility methods used to explicitly bind a function\'s execution context (this). Both call and apply invoke functions immediately; the syntactic difference lies in their signature, where call accepts arguments as a comma-separated sequence and apply accepts arguments wrapped in a single array. bind differs by returning a new closure where the context and initial arguments are locked, allowing deferred execution. A custom implementation of bind leverages closures to hold references to the target function and initial arguments, returning a nested wrapper that executes the target function using Function.prototype.apply to merge initial binding parameters with active invocation parameters.

    Đọc lời giải đầy đủ
  3. Nâng caoJavaScript14 phút đọc

    What is a closure in JavaScript?

    Gợi ý trả lời

    A closure is formed when a function retains access to variables from its lexical scope even after the outer function has completed execution. JavaScript functions capture references to their surrounding environment at creation time, allowing those variables to remain accessible later. Closures power many important JavaScript patterns including data encapsulation, event handlers, debouncing, throttling, memoization, and React Hooks. While closures are extremely useful, they can also increase memory usage because referenced variables cannot be garbage collected until all closures referencing them are removed.

    Đọc lời giải đầy đủ
  4. Trung cấpJavaScript7 phút đọc

    What is currying, and how does it differ from partial application? How do closures support these patterns, and how would you implement a function to handle infinite currying?

    Gợi ý trả lời

    Currying is a functional transformation that splits a multi-argument function of arity $N$ into a series of unary functions that resolve on the $N$-th invocation. Partial application fixes a subset of arguments ahead of execution, yielding a function that accepts the remaining parameters. Both patterns rely on JavaScript closures, which retain access to variables in their lexical environment after outer functions return. A custom curry wrapper evaluates the accumulated arguments length against the expected target function length. If the argument quota is met, it executes the target function; otherwise, it returns a closure that merges existing arguments with incoming ones via recursion.

    Đọc lời giải đầy đủ
  5. Trung cấpJavaScript12 phút đọc

    What is the difference between Debounce and Throttle?

    Gợi ý trả lời

    Debounce and throttle are performance optimization techniques used to control the frequency of function execution. Debounce delays execution until a period of inactivity has passed, making it ideal for search inputs, form validation, and auto-save features. Throttle limits execution to at most once per specified interval, making it ideal for scroll, resize, and mouse movement events. Internally, both techniques rely on closures to maintain state between invocations. The choice depends on whether the application needs the final event only (debounce) or regular updates during continuous activity (throttle).

    Đọc lời giải đầy đủ
  6. Cơ bảnJavaScript6 phút đọc

    What are event bubbling, event capturing, and event delegation in JavaScript? How do they work, and why is event delegation beneficial for performance?

    Gợi ý trả lời

    DOM event propagation operates in three phases: capturing, target, and bubbling. In event delegation, we exploit the bubbling phase by mounting a single event listener on a common parent ancestor rather than mounting hundreds of individual listeners on list items. This drastically reduces runtime memory usage and page-load CPU cycles. When an event fires, it bubbles up to the ancestor, where we compare event.target (the interaction source node) with a match condition using selector functions like .closest(). This pattern also naturally accommodates dynamic DOM mutations, as new nodes appended under the parent container immediately trigger the parent delegation listener without requiring manual event registration or teardown bindings.

    Đọc lời giải đầy đủ
  7. Nâng caoJavaScript16 phút đọc

    How does the JavaScript Event Loop work?

    Gợi ý trả lời

    JavaScript is single-threaded and executes code using a Call Stack. Asynchronous operations such as timers, network requests, and DOM events are handled by browser Web APIs. Once completed, their callbacks are placed into task queues. The Event Loop continuously checks whether the Call Stack is empty and then moves queued tasks onto the stack for execution. Promise callbacks and async/await continuations are scheduled as Microtasks, while setTimeout callbacks are scheduled as Macrotasks. The Event Loop always processes all Microtasks before executing the next Macrotask, which is why Promise callbacks execute before timers.

    Đọc lời giải đầy đủ
  8. Nâng caoJavaScript12 phút đọc

    The Call Stack, Memory Heap, and Execution Context in JavaScript

    Gợi ý trả lời
    • The Execution Context is the environment where JavaScript code is evaluated.
    • The Call Stack uses LIFO order to manage function calls and store primitive values.
    • The Memory Heap allocates unstructured memory for dynamically-sized objects, arrays, and closures.
    • The stack stores *references* (pointers) to objects that reside in the heap.
    • Modern engines use Mark-and-Sweep garbage collection, tracing memory from global and stack roots to clean unreachable allocations.
    • Keep functions shallow and clear references to unused large data sets to avoid stack overflows and memory heap leaks.
    Đọc lời giải đầy đủ
  9. Nâng caoJavaScript8 phút đọc

    What are iterators and generator functions in JavaScript? How does the iterator protocol work, and how do you write an async generator to poll or stream data chunk-by-chunk?

    Gợi ý trả lời

    The Iterator protocol requires a Symbol.iterator method that returns an object containing a .next() signature, which outputs { value, done } objects. Generator functions (function*) act as factory routines for Iterators. They suspend their execution contexts and call stacks upon hitting a yield statement, resuming state parameters only when .next() is called. In asynchronous environments, Async Generators (async function*) throw or yield Promises at each suspend boundary, allowing developers to consume chunked or paginated network streams natively using for await...of loops. This provides a highly clean, sequential way to handle asynchronous streams without managing raw callbacks or streams API complexities.

    Đọc lời giải đầy đủ
  10. Trung cấpJavaScript12 phút đọc

    What is hoisting in JavaScript?

    Gợi ý trả lời

    Hoisting is JavaScript's behavior of creating bindings for variables and functions during the creation phase of an execution context before code execution begins. Variable declarations using var are hoisted and initialized with undefined, while let and const are hoisted but remain uninitialized inside the Temporal Dead Zone until their declaration is evaluated. Function declarations are fully hoisted, allowing them to be invoked before their definition appears in the source code. Hoisting is not the physical movement of code but a consequence of how JavaScript builds execution contexts.

    Đọc lời giải đầy đủ
  11. Trung cấpJavaScript10 phút đọc

    JavaScript Scopes: Global, Function, and Lexical Scope

    Gợi ý trả lời
    • Scope defines variable visibility rules.
    • Var is function-scoped; Let/Const are block-scoped (restricting access to curly braces {}).
    • JavaScript is Lexically Scoped—scoping is determined by where functions are written in the source code, not where they are executed.
    • The Scope Chain is the path resolved by the engine looking up nested parent lexical environments.
    • Shadowing occurs when a local variable hides an outer variable of the same name.
    • Always use 'use strict' or ESM to prevent accidental global scope leakages.
    Đọc lời giải đầy đủ
  12. Cơ bảnJavaScript8 phút đọc

    What is the difference between map, filter, and reduce in JavaScript? When should you use each?

    Gợi ý trả lời

    In JavaScript, map, filter, and reduce are functional, non-mutating array methods used for traversing and transforming collections. map creates a new array of the same length by applying a callback to each element. filter creates a subset array containing only elements that return truthy from a predicate callback. reduce iterates over the array to accumulate its values into a single return value—which can be a number, string, array, or object—based on an accumulator parameter and an optional initial value. Because map and filter return arrays, they support declarative chaining, allowing developers to avoid imperative for loops and state mutations.

    Đọc lời giải đầy đủ
  13. Nâng caoJavaScript14 phút đọc

    What is a memory leak in JavaScript?

    Gợi ý trả lời

    A memory leak occurs when memory that is no longer needed remains reachable and therefore cannot be reclaimed by JavaScript's garbage collector. Since JavaScript uses automatic memory management, developers do not manually free memory, but they are responsible for removing unnecessary references. Common sources of leaks include global variables, closures retaining large objects, event listeners, timers, detached DOM nodes, unbounded caches, and improperly cleaned React effects. Garbage collection can only remove unreachable objects, so memory leaks occur when references remain alive longer than intended.

    Đọc lời giải đầy đủ
  14. Cơ bảnJavaScript6 phút đọc

    What is the difference between Primitive and Reference types in JavaScript? How are they stored in memory?

    Gợi ý trả lời

    JavaScript separates data into primitive types and reference types based on storage mechanics. Primitive types are stored directly in stack memory by value, meaning copy actions duplicate the actual value. Reference types, such as objects and arrays, reside in heap memory, and their variables in the stack store pointers pointing to their heap address. Consequently, assigning an object to another variable simply copies the reference, meaning mutations propagate to all variables pointing to that heap location. To replicate objects independently, developers must choose between a shallow copy (using spreads or Object.assign) or a deep copy (using structuredClone) depending on the complexity of nested properties.

    Đọc lời giải đầy đủ
  15. Nâng caoJavaScript14 phút đọc

    Programming Paradigms in JavaScript: Functional vs. Object-Oriented

    Gợi ý trả lời
    • Multi-Paradigm: JavaScript supports both FP and OOP, allowing you to choose the best pattern for the specific task.
    • OOP encapsulates state and methods inside mutable objects, inheriting behavior via prototype delegation.
    • FP relies on pure functions, data immutability, and function composition to create highly testable and predictable pipelines.
    • Prefer Composition over Inheritance to avoid rigid class models and fragile structures.
    • Modern React patterns (like Hooks and functional components) lean heavily Functional, whereas utility libraries and backend Node systems frequently combine both styles.
    Đọc lời giải đầy đủ
  16. Nâng caoJavaScript15 phút đọc

    What is a Promise and why do we need it?

    Gợi ý trả lời

    A Promise is an object that represents the eventual completion or failure of an asynchronous operation. It can be in one of three states: pending, fulfilled, or rejected. Promises solve callback hell by providing a structured way to compose asynchronous operations through chaining. Methods such as then, catch, and finally allow success handling, error handling, and cleanup. Promise callbacks are scheduled in the Microtask Queue, which gives them higher priority than timer callbacks in the Event Loop. Modern async/await syntax is built on top of Promises and provides a cleaner way to write asynchronous code.

    Đọc lời giải đầy đủ
  17. Nâng caoJavaScript14 phút đọc

    How does inheritance work in JavaScript?

    Gợi ý trả lời

    JavaScript uses prototype-based inheritance rather than classical inheritance. Every object has an internal reference to another object known as its prototype. When a property or method is accessed, JavaScript first searches the object itself and then walks up the prototype chain until it finds the property or reaches null. Constructor functions and ES6 classes both rely on this mechanism internally. Methods placed on a constructor's prototype are shared across all instances, making prototype inheritance memory efficient and fundamental to JavaScript's object-oriented model.

    Đọc lời giải đầy đủ
  18. Cơ bảnJavaScript6 phút đọc

    What is the difference between double equals (==) and triple equals (===) in JavaScript?

    Gợi ý trả lời

    Double equals (==) compares values after performing implicit type coercion, trying to convert both operands to a matching primitive type (usually numeric). Triple equals (===) compares both the value and the type strictly, returning false if types do not align. For example, 5 == "5" evaluates to true because the string is coerced to a number, whereas 5 === "5" is false due to type mismatch. Because loose coercion rules lead to unintuitive behaviors (like [] == false evaluating to true), strict equality (===) is the industry standard for code predictability, with double equals reserved almost exclusively for checking if a value is null or undefined simultaneously (val == null).

    Đọc lời giải đầy đủ
  19. Trung cấpJavaScript12 phút đọc

    What is this in JavaScript and how does it work?

    Gợi ý trả lời

    The value of this in JavaScript is determined by how a function is invoked. In global scope, this usually refers to the global object. In object methods, it refers to the object before the dot. Constructor functions bind this to newly created instances via new. Functions can explicitly set this using call, apply, and bind. Arrow functions are different because they do not have their own this; instead they inherit it lexically from the surrounding scope. Understanding invocation patterns rather than memorizing rules is the key to mastering this.

    Đọc lời giải đầy đủ
  20. Trung cấpJavaScript7 phút đọc

    What are WeakMap and WeakSet in JavaScript? How do they differ from Map and Set, and what specific problem do they solve regarding garbage collection?

    Gợi ý trả lời

    The fundamental difference between Map and WeakMap is the reference strength of keys. A Map establishes strong references, preventing garbage collection of key objects. A WeakMap holds weak references to its keys, meaning if a key object lacks other active references in the execution stack, it is garbage collected, and its entry is cleared from the WeakMap automatically. To make this garbage collection lookup deterministic, WeakMap keys must be object types rather than primitive values, and the collection is non-iterable, preventing exposure of intermediate garbage collection states. Major use cases include metadata association for DOM nodes, private scoping structures, and non-blocking caching layers.

    Đọc lời giải đầy đủ
  21. Cơ bảnTypeScript6 phút đọc

    What is the difference between any and unknown in TypeScript? When should you choose one over the other?

    Gợi ý trả lời
    • unknown Type: Use unknown by default when you don't know the incoming type (e.g., fetch request responses, dynamic input fields) to keep the codebase type-safe.
    • any Type: Avoid any unless migrating legacy JavaScript or writing complex generic libraries where type safety is managed via other assertions.
    • Top Type Behavior: Both any and unknown are top types (all values are assignable to them), but unknown cannot be assigned to anything else without narrowing.
    Đọc lời giải đầy đủ
  22. Trung cấpTypeScript7 phút đọc

    What are declaration files (.d.ts) in TypeScript, and how does declaration merging work? Give a concrete example of how to extend a third-party library's interface (e.g. Express Request object) using module augmentation.

    Gợi ý trả lời

    Declaration files (.d.ts) act as compile-time metadata describing JavaScript interfaces to the compiler without emitting runtime code. Declaration merging occurs when the compiler combines identical-named interfaces, namespaces, or classes into a unified construct. When extending third-party module interfaces (such as adding authenticated user fields to Express request items), standard global scope interfaces fail because of module isolation. We resolve this by declaring module augmentation using declare module 'module-name' or declare global blocks. Inside these blocks, we redeclare target interfaces, triggering interface merging, which expands the compiler\'s type registry for those library modules.

    Đọc lời giải đầy đủ
  23. Nâng caoTypeScript8 phút đọc

    What are Mapped Types and Template Literal Types in TypeScript? How do you use key remapping (the as clause) to dynamically transform object key names or filter keys during compilation?

    Gợi ý trả lời

    Mapped types iterate over a set of keys to dynamically generate object structures. Template literal types build upon string union types, allowing string concatenations and modifications to resolve at compile-time. We can combine these features using key remapping via the as clause to rename keys dynamically (e.g. capitalizing properties to output getter signatures) or filter out keys. By resolving key definitions to never inside a conditional type check during the as remapping cycle, TypeScript excludes those properties entirely, providing a declarative mechanism to implement custom utility transformations.

    Đọc lời giải đầy đủ
  24. Cơ bảnTypeScript6 phút đọc

    How do you declare immutable properties in TypeScript? What is the difference between readonly, the Readonly<T> utility type, and as const assertions?

    Gợi ý trả lời
    • readonly Modifier: Prevents properties on an interface or class from being reassigned after initialization.
    • Readonly Utility: Wraps an entire object type to make all its properties read-only without manual keys.
    • as const Assertions: Locks down literal values recursively to read-only, preventing type widening to primitive types.
    • ReadonlyArray: Prevents mutating array methods like push and pop from running on an array at compile-time.
    Đọc lời giải đầy đủ
  25. Cơ bảnTypeScript6 phút đọc

    What is a Type Assertion in TypeScript, and how does it differ from Type Casting in JavaScript or other languages?

    Gợi ý trả lời
    • No Runtime Impact: Type assertions are removed during compilation; they do not validate or modify runtime values.
    • as vs Angle-Bracket: Always prefer as to remain compatible with TSX files.
    • as const: Use const assertions when you want to define configuration values, enums, or strict static lookup keys.
    Đọc lời giải đầy đủ
  26. Trung cấpTypeScript8 phút đọc

    What is Type Narrowing in TypeScript, and how do you write a custom (User-Defined) Type Guard using the is keyword?

    Gợi ý trả lời
    • Type Predicates: Return parameterName is Type from a function to tell the compiler that returning true guarantees the variable type.
    • Narrowing Operators: Leverage typeof, instanceof, and in for standard Javascript object structures.
    • discriminated unions: Use literal fields to create robust control flows that scale without writing manual checks.
    • exhaustive checking: Use the never type in your switch fallbacks to guarantee all union states are handled.
    Đọc lời giải đầy đủ
  27. Nâng caoTypeScript6 phút đọc

    TypeScript Generics and Built-in Utility Types

    Gợi ý trả lời
    • Generics: Write code that remains flexible while maintaining strict compile-time types.
    • Utility Types: Standard utilities like Pick and Omit use mapped types under the hood to transform object shapes.
    • infer Keyword: Allows you to extract type parameters out of functions, arrays, and promises dynamically.
    Đọc lời giải đầy đủ
  28. Nâng caoTypeScript6 phút đọc

    TypeScript Conditional Types and the infer Keyword

    Gợi ý trả lời
    • Conditional types allow writing if/else checks within the type system using T extends U ? X : Y.
    • The infer keyword is a powerful pattern-matching tool that declares a generic variable on-the-fly inside a condition.
    • infer can only be placed inside the extends clause of a conditional type.
    • Common utilities like ReturnType, Parameters, and Awaited are built entirely on top of the infer keyword.
    Đọc lời giải đầy đủ