- Sự khác biệt giữa var, let và const là gì?
var, let và const đều khai báo biến trong JavaScript, nhưng khác nhau về scope, hành vi khai báo lại, và khả năng gán lại giá trị. - var có function scope — biến "lan" ra toàn bộ function chứa nó, bất kể nó được…
- JavaScript có những kiểu dữ liệu nguyên thuỷ (primitive types) nào?
JavaScript có 7 kiểu nguyên thuỷ: string, number, boolean, null, undefined, symbol, bigint. Đặc điểm chung: bất biến và sao chép theo giá trị. Không phải nguyên thuỷ: object, array, function, Date, Map, Set — tất cả đều là object và sao chép theo tham…
- Symbol trong JavaScript là gì và dùng để làm gì?
Symbol là kiểu dữ liệu nguyên thuỷ tạo ra một giá trị duy nhất (unique). Mỗi lần gọi Symbol() sẽ tạo ra một giá trị hoàn toàn khác biệt, ngay cả khi có cùng mô tả (description). Ứng dụng chính: - Tránh xung đột tên…
- Toán tử == và === khác nhau như thế nào?
== so sánh sau khi ép kiểu; === so sánh cả giá trị lẫn kiểu, không ép. Bảng ép kiểu của == có nhiều trường hợp phản trực giác, đó là lý do gần như mọi bộ quy tắc lint đều bật eqeqeq. Ngoại lệ…
- Type coercion (ép kiểu tự động) trong JavaScript là gì?
Type coercion là việc JavaScript tự đổi kiểu khi phép toán nhận hai kiểu khác nhau. Hai luật chi phối gần hết các trường hợp: 1. + ưu tiên chuỗi — chỉ cần một toán hạng là chuỗi thì thành nối chuỗi. 2. Mọi toán…
- Truthy và falsy values trong JavaScript là gì?
Falsy là giá trị bị coi là false khi đưa vào ngữ cảnh boolean. Có đúng 8 giá trị, học thuộc là đủ: Mọi thứ còn lại đều truthy — kể cả những thứ trông như "rỗng": Lưu ý — số 0 và chuỗi rỗng…
- NaN là gì? Tại sao NaN !== NaN?
NaN (Not a Number) là kết quả của một phép toán số không ra kết quả hợp lệ: Theo chuẩn IEEE 754, NaN không bằng bất cứ giá trị nào — kể cả chính nó. Đây là quy định của chuẩn số học dấu chấm…
- Hoisting trong JavaScript là gì?
Hoisting là cách JavaScript engine tạo binding cho các khai báo trước khi thực thi code từng dòng trong scope. Bạn có thể hình dung như ban tổ chức lập danh sách chỗ ngồi trước khi khách đến. Tên đã có trong danh sách, nhưng…
- Temporal Dead Zone (TDZ) là gì?
TDZ là khoảng từ đầu block tới dòng khai báo của một biến let/const. Trong khoảng đó biến đã tồn tại nhưng chưa khởi tạo, truy cập sẽ ném ReferenceError. Dòng typeof x là điểm hay được hỏi: typeof vốn an toàn với biến chưa…
- Scope chain trong JavaScript hoạt động như thế nào?
Scope chain là cơ chế JavaScript tìm kiếm biến từ scope hiện tại ra ngoài đến global scope. Khi không tìm thấy biến trong scope hiện tại, JS tìm trong scope cha, rồi tiếp tục lên cho đến global. Nếu không tìm thấy ở global,…
- Closure là gì? Cho ví dụ thực tế.
Closure là hàm 'nhớ' được biến từ lexical scope bên ngoài, ngay cả sau khi hàm ngoài đã return. Hàm trả về vẫn truy cập count. Ứng dụng thực tế: private variables (encapsulation), factory functions, event handlers giữ state, debounce/throttle, React hooks (useState bên trong…
- Closure có thể gây memory leak như thế nào?
- Vấn đề classic về closure trong vòng lặp with var là gì?
Khi dùng var trong vòng lặp for, tất cả callback chia sẻ cùng tham chiếu đến biến i — vì var là function scope, chỉ có một biến i duy nhất. Đây là câu hỏi phỏng vấn cổ điển về closure.
- Sự khác biệt giữa function declaration và function expression trong hoisting là gì?
Function declaration được hoisted hoàn toàn (cả tên và thân hàm), có thể gọi trước khi khai báo. Function expression chỉ hoisted phần khai báo biến (với var là undefined), không thể gọi trước khi gán.
- Tại sao var trong global scope tạo property trên window object?
- Stale closure là gì và cách phòng tránh?
- Sự khác biệt giữa function declaration, function expression và arrow function là gì?
Ba cách viết hàm, khác nhau ở hoisting, this, và những gì hàm có sẵn. declaration expression arrow ------------ Hoist cả thân hàm có không không this riêng có có không (lấy từ scope ngoài) arguments có có không Dùng với new được được không…
- Callback function là gì? Tại sao JavaScript dùng callbacks?
Callback là hàm truyền vào một hàm khác để được gọi lại sau. JavaScript chạy một luồng. Nếu phải chờ mạng hay đĩa theo kiểu chặn, cả giao diện đứng im. Callback cho phép đăng ký "làm việc này khi có kết quả" rồi trả…
- Higher-order function là gì? Cho ví dụ.
Higher-order function (HOF) là hàm nhận hàm làm tham số, trả về hàm, hoặc cả hai. HOF có mặt ở khắp nơi trong thực tế: - map, filter, reduce, sort, forEach - middleware Express: (req, res, next) = {} - useMemo, useCallback, HOC trong React…
- IIFE (Immediately Invoked Function Expression) là gì và dùng để làm gì?
IIFE là hàm được định nghĩa và gọi ngay lập tức. Cặp ngoặc bọc ngoài là bắt buộc: nó biến function declaration thành function expression, để có thể gọi ngay. Trước ES6, JavaScript chỉ có function scope — IIFE là cách duy nhất để tạo…
- Pure function là gì? Tại sao pure functions quan trọng?
Pure function thoả hai điều kiện: 1. Cùng input luôn cho cùng output. 2. Không có side effect — không sửa gì bên ngoài phạm vi của nó. Lợi ích thực tế: - Test không cần mock — gọi hàm, so kết quả, hết. -…
- Currying là gì? Cho ví dụ và trường hợp dùng thực tế.
- Memoization là gì? Cài đặt memoization đơn giản như thế nào?
- Rest parameters (...args) là gì? Khác gì arguments object?
...args gom mọi tham số còn lại thành một Array thật. So với arguments: ...rest arguments --------- Kiểu Array thật array-like, phải Array.from() Nội dung chỉ phần chưa đặt tên toàn bộ tham số Trong arrow function có không Đặt tên được có không Đừng…
- Function composition là gì?
Function composition là ghép nhiều hàm nhỏ thành một hàm lớn, đầu ra của hàm này là đầu vào của hàm kế tiếp. Hai cái chỉ khác chiều đọc: Lợi ích so với biến trung gian: Gặp ở đâu trong thực tế: applyMiddleware của Redux,…
- Generator function là gì? Dùng khi nào?
- Callback hell là gì? Các giải pháp để tránh?
Callback hell là khi các callback bất đồng bộ lồng vào nhau nhiều tầng, code thụt lề thành hình kim tự tháp và code xử lý lỗi bị lặp lại ở mọi tầng. Hai vấn đề thật, không chỉ là xấu: lỗi phải xử lý…
- Quy tắc xác định giá trị của this trong JavaScript là gì?
this không phụ thuộc nơi hàm được định nghĩa mà phụ thuộc cách hàm được gọi. Bốn quy tắc, xét theo thứ tự ưu tiên giảm dần: Arrow function không nằm trong bốn quy tắc này — nó không có this riêng mà lấy từ…
- strict mode ảnh hưởng đến this như thế nào?
Trong strict mode, this ở hàm thông thường là undefined thay vì global object (window/global). Điều này giúp phát hiện lỗi khi vô tình gọi hàm như function thay vì method. Kích hoạt bằng 'use strict'; ở đầu file hoặc hàm. ES modules tự động…
- Sự khác biệt giữa call(), apply() và bind() là gì?
Cả ba đều đặt this một cách tường minh, khác nhau ở cách truyền tham số và thời điểm gọi. Gọi ngay Tham số Trả về ------------ call có rời từng cái kết quả hàm apply có một mảng kết quả hàm bind không rời…
- Tại sao arrow function không phù hợp làm method trong object?
Arrow function không có this riêng, kế thừa this từ lexical scope nơi nó được định nghĩa. Khi dùng làm method, this không trỏ đến object chứa method. Dùng function thông thường cho methods, arrow function cho callbacks bên trong method.
- Constructor function và new keyword hoạt động như thế nào?
Gọi new Foo() khiến JavaScript làm bốn việc theo thứ tự: Tự cài lại new để thấy rõ: Quy tắc ở bước 4 hay bị hỏi: return giá trị nguyên thuỷ thì bị bỏ qua, chỉ return object mới ghi đè được this. Lưu ý:…
- this trong class JavaScript là gì?
Trong class, this trong constructor và methods trỏ đến instance được tạo. Tuy nhiên, khi truyền method như callback, mất this binding. Giải pháp: dùng arrow function trong class fields (tự bind), bind trong constructor, hoặc .bind() khi truyền callback.
- Prototype chain trong JavaScript là gì?
Prototype chain là đường JavaScript đi tìm thuộc tính. Nếu obj.name không có trên obj, JS tìm tiếp trên prototype... cho tới khi gặp null thì dừng.
- __proto__ và prototype khác nhau như thế nào?
proto là instance link — nằm trên object instance. prototype là blueprint — nằm trên constructor function. Khi dùng new Foo(), object mới có proto trỏ tới Foo.prototype. Trong code thực tế, dùng Object.getPrototypeOf(obj) thay vì truy cập proto trực tiếp.
- Object.create() hoạt động như thế nào?
Object.create(proto) tạo object mới với prototype là proto. Object con dùng được method từ proto qua prototype chain.
- instanceof operator hoạt động như thế nào?
obj instanceof Foo kiểm tra: Foo.prototype có nằm trong prototype chain của obj không. Lưu ý: qua iframe/vm khác realm, instanceof có thể cho kết quả không như mong đợi.
- hasOwnProperty() và in operator khác nhau như thế nào?
- Prototype pollution là gì và cách phòng tránh?
- Destructuring assignment là gì? Cho ví dụ với array và object.
Destructuring cho phép tách giá trị từ array/object ra từng biến. Hỗ trợ default values, alias, và nested destructuring.
- Spread operator (...) và rest parameters (...) khác nhau như thế nào?
Spread trải iterable ra thành từng phần tử (dùng trong function calls, array literals, object literals). Rest thu thập nhiều phần tử thành array (dùng trong function parameters). Cú pháp giống nhau nhưng ngữ cảnh ngược nhau.
- Template literals là gì? Có những tính năng gì?
Template literals dùng backtick thay dấu nháy, hỗ trợ: interpolation ${expression}, multi-line strings, tagged templates. Tagged templates là function nhận template strings và expressions làm arguments.
- Class trong ES6 là gì? Có điểm gì khác với function constructor?
Class là cú pháp OOP rõ ràng hơn để tạo objects. Khác function constructor: class không thể gọi không có new (throw TypeError), methods không enumerable (không xuất hiện trong for...in), và phải khai báo trước khi dùng (không hoisted). Bên dưới vẫn dùng prototype…
- Private class fields (#) là gì?
Private field khai báo bằng tiền tố , chỉ truy cập được bên trong thân class. Đây là private thật ở tầng engine, khác hẳn quy ước name: Kiểm tra một object có phải instance có field đó không — cú pháp in cho private…
- for...of và for...in khác nhau như thế nào?
for...in duyệt key, for...of duyệt value. for...in for...of --------- Duyệt key enumerable value của iterable Đi lên prototype chain có không Dùng với object thường Array, String, Map, Set, NodeList, generator Object thường được TypeError — không iterable Hai lý do không nên dùng for...in…
- Map và WeakMap khác nhau như thế nào?
Khác nhau ở kiểu key và quan hệ với garbage collector. Map WeakMap --------- Key bất kỳ kiểu nào chỉ object / symbol Duyệt được có không size có không Giữ key sống có không (weak reference) Ý nghĩa của "weak": key bị mất mọi…
- Set và WeakSet là gì?
Set là tập hợp giá trị không trùng lặp; WeakSet là bản chỉ chứa object và giữ tham chiếu yếu. So sánh trong Set dùng SameValueZero, nên hành vi với NaN khác ===: WeakSet chỉ có add/has/delete, không size, không duyệt: Chọn thế nào: cần…
- ES modules (import/export) là gì?
ES module là hệ thống module chuẩn của JavaScript, chạy được cả trên browser lẫn Node. Bốn đặc điểm cần nhớ: 1. Phân tích tĩnh — import/export được xác định lúc phân tích cú pháp, không phải lúc chạy. Đây là điều kiện để bundler…
- Proxy và Reflect trong ES6 là gì?
Proxy bọc object và chặn các operation (get, set, has, deleteProperty...) bằng handler traps. Reflect cung cấp methods tương ứng với các traps. Dùng để tạo reactive objects (Vue 3), validation, logging, lazy initialization, hay implement Observable.
- Symbol.iterator và iterable protocol là gì?
- Object.assign() và spread operator khi copy object khác nhau như thế nào?
Cả hai đều shallow copy. Object.assign() copy vào object đích hiện có, trigger setters trên target. Spread tạo plain object mới, không trigger setters. Object.assign() copy enumerable own properties bao gồm cả Symbol. Với nested objects, cả hai chỉ copy reference, không deep copy.
- Logical assignment operators (&&=, ||=, ??=) là gì?
- Array.from() vs spread operator khi chuyển đổi array-like là gì?
- String methods mới trong ES6+ như padStart, padEnd, includes, startsWith là gì?
Nhóm method chuỗi thêm từ ES6 trở đi, thay được phần lớn regex đơn giản: Hai điểm hay bị hỏi thêm: 1. includes phân biệt hoa thường — muốn không phân biệt phải tự chuẩn hoá: 2. replaceAll với chuỗi thì an toàn, với regex…
- at() method cho Array và String là gì?
at(index) truy cập phần tử và hỗ trợ chỉ số âm. So với cách viết cũ: Vì sao arr[-1] không chạy: trong JavaScript, chỉ số của mảng thực chất là key kiểu chuỗi của object. arr[-1] tra key '-1', một thuộc tính thường không tồn…
- Promise là gì? Có những trạng thái nào?
Promise là object đại diện cho kết quả mà tác vụ async sẽ trả về sau (ví dụ gọi API). Nó có 3 trạng thái: - pending: đang chờ - fulfilled: thành công (resolve) - rejected: thất bại (reject) Một khi đã fulfilled hoặc rejected…
- .then(), .catch() và .finally() hoạt động như thế nào?
- .then(...): chạy khi Promise thành công. - .catch(...): chạy khi có lỗi ở Promise trước đó. - .finally(...): luôn chạy sau cùng (dù thành công hay lỗi). Ví dụ: Mẹo cho người mới: dùng finally để dọn trạng thái UI như loading.
- Event loop trong JavaScript hoạt động như thế nào?
- Microtask và macrotask khác nhau như thế nào?
Cả hai đều là hàng đợi công việc bất đồng bộ, nhưng microtask được ưu tiên tuyệt đối. Microtask Macrotask --------- Nguồn .then/.catch/.finally, await, queueMicrotask, MutationObserver setTimeout, setInterval, sự kiện I/O, sự kiện DOM Khi nào chạy hết sạch queue sau mỗi macrotask một cái…
- async/await là gì? Tại sao nó dễ hơn Promise chains?
async/await là cú pháp viết Promise theo kiểu gần giống code đồng bộ, nên dễ đọc hơn chain .then(). Ví dụ: Điểm cần nhớ: - await chỉ dùng trong hàm async - lỗi nên bắt bằng try/catch - bản chất bên dưới vẫn là Promise.
- Xử lý lỗi trong async/await như thế nào?
Dùng try/catch bọc await expressions. Lỗi từ rejected Promise được catch như exception.
- Async iteration (for await...of) là gì?
- setTimeout(fn, 0) có thực sự chạy ngay không?
Không. setTimeout(fn, 0) đưa callback vào macrotask queue, nên nó chỉ chạy sau khi call stack rỗng và toàn bộ microtask đã xử lý xong. Ngoài ra spec HTML quy định độ trễ tối thiểu 4ms khi timer lồng từ tầng thứ 5 trở đi:…
- Abort controller dùng để huỷ fetch request như thế nào?
- Race condition trong async JavaScript là gì và cách xử lý?
Race condition xảy ra khi nhiều tác vụ bất đồng bộ chạy chồng nhau và kết quả phụ thuộc vào cái nào về trước — thứ tự đó không được đảm bảo. Trường hợp thường gặp: ô tìm kiếm gõ nhanh, phản hồi cũ về…
- async/await với parallel execution như thế nào?
- Unhandled promise rejection là gì? Cách xử lý?
Unhandled rejection là khi một Promise bị reject mà không có handler nào bắt — không .catch(), không try/catch quanh await. Hậu quả khác nhau theo môi trường: Hành vi mặc định ------ Node 15+ kết thúc tiến trình (đổi được bằng --unhandled-rejections=warn) Browser ghi…
- Task scheduling trong JavaScript: requestAnimationFrame và requestIdleCallback là gì?
- Long tasks và JavaScript performance liên quan đến event loop như thế nào?
- DOM là gì? JavaScript tương tác với DOM như thế nào?
DOM (Document Object Model) là biểu diễn dạng cây của HTML document, mỗi element là một node. JavaScript tương tác qua document API: querySelector, createElement, appendChild, setAttribute... DOM manipulation là synchronous, thay đổi DOM ngay lập tức reflect trên page.
- Sự khác biệt giữa getElementById, querySelector và querySelectorAll là gì?
Khác nhau ở cách chọn, kiểu trả về, và có cập nhật theo DOM hay không. Trả về Sống / tĩnh Duyệt bằng forEach ------------ getElementById Element hoặc null — — querySelector Element hoặc null — — querySelectorAll NodeList tĩnh được getElementsBy HTMLCollection sống không…
- Event delegation là gì? Tại sao nó hiệu quả?
Event delegation là gắn một listener trên phần tử cha thay vì gắn cho từng phần tử con, rồi dựa vào event bubbling để biết ai vừa được bấm. Ba lợi ích: 1. Ít bộ nhớ hơn — một listener thay vì hàng nghìn. 2.…
- preventDefault() và stopPropagation() khác nhau như thế nào?
Hai việc hoàn toàn khác nhau: một cái chặn hành vi mặc định của browser, một cái chặn đường đi của sự kiện. preventDefault() stopPropagation() --------- Chặn hành vi mặc định (submit, theo link, tick checkbox) bubbling / capturing Sự kiện còn đi tiếp có…
- Fetch API là gì? Khác XMLHttpRequest như thế nào?
fetch() là API HTTP dựa trên Promise, thay cho XMLHttpRequest. Điểm gây bất ngờ nhất — fetch không reject khi server trả lỗi: Đây là lý do mọi wrapper fetch trong dự án thật đều bắt đầu bằng if (!res.ok) throw .... fetch XMLHttpRequest ---------…
- Web Workers là gì? Khi nào nên dùng?
Web Worker chạy JavaScript trên một luồng riêng, nên tính toán nặng không làm đứng giao diện. Worker không truy cập được DOM, window, document. Nó có fetch, WebSocket, IndexedDB, crypto — đủ cho phần lớn việc xử lý dữ liệu. Dữ liệu qua postMessage…
- IntersectionObserver API là gì và dùng để làm gì?
IntersectionObserver báo bất đồng bộ khi một element đi vào (hoặc rời khỏi) viewport hay một container. Vì sao hơn scroll listener: callback không chạy trên đường cuộn, browser tự gộp nhiều element, và không có getBoundingClientRect() mỗi khung hình gây layout thrashing. Dùng cho:…
- MutationObserver là gì?
MutationObserver theo dõi thay đổi trên DOM tree (attribute changes, child additions/removals, text changes). Asynchronous, callbacks chạy như microtask. Hữu ích khi làm việc với third-party code thay đổi DOM, implement undo/redo, hay real-time updates. ResizeObserver theo dõi thay đổi kích thước element.
- Cookie, localStorage và sessionStorage khác nhau như thế nào về bảo mật và sử dụng?
Ba nơi lưu dữ liệu ở client, khác nhau ở ai đọc được, tồn tại bao lâu, và có gửi lên server không. Cookie localStorage sessionStorage ------------ Dung lượng ~4KB ~5–10MB ~5–10MB Gửi kèm mọi request có không không JS đọc được có, trừ khi…
- Custom events trong JavaScript là gì?
CustomEvent cho phép tạo events tuỳ chỉnh với data đính kèm. Dispatch với element.dispatchEvent(event). Bubbles và cancelable tuỳ chỉnh được. Dùng cho component communication không dùng framework, pub/sub pattern trong vanilla JS.
- requestAnimationFrame là gì và tại sao nên dùng thay setTimeout cho animations?
requestAnimationFrame(cb) xếp lịch cho callback chạy ngay trước lần vẽ tiếp theo của browser. Ba lý do hơn setTimeout(fn, 16): 1. Đồng bộ với nhịp vẽ thật của màn hình — đúng cả trên màn 120Hz, không bị lệch khung gây giật. 2. Tự dừng…
- Service Workers là gì?
- Sự khác biệt giữa textContent, innerText và innerHTML là gì?
innerHTML: get/set HTML markup (nguy cơ XSS nếu set user input). textContent: get/set text của tất cả nodes kể cả ẩn, không trigger reflow. innerText: chỉ lấy text hiển thị (aware of CSS), trigger reflow để tính style. textContent nhanh nhất và an toàn nhất…
- IndexedDB là gì? Khi nào dùng thay localStorage?
- Viết hàm debounce từ đầu (không dùng lodash)?
Debounce trì hoãn execution cho đến khi input ngừng, tránh gọi API quá nhiều lần. Ứng dụng: search input (gõ xong 300ms mới gọi API), resize handler, auto-save. Phỏng vấn thường hỏi viết tay để kiểm tra hiểu closure và timer.
- Viết hàm throttle từ đầu?
Throttle giới hạn call rate xuống tối đa một lần mỗi interval — gọi ngay lần đầu rồi chặn. Khác debounce: throttle gọi ngay lần đầu rồi chặn, debounce đợi hết delay mới gọi. Dùng cho scroll, mousemove.
- Implement deep clone object (không dùng structuredClone)?
Deep clone sao chép đệ quy toàn bộ nested values mà không giữ reference gốc. Lưu ý: không handle Date, RegExp, Map, Set, circular refs. Production dùng structuredClone() hoặc lodash.
- Flatten nested array (không dùng Array.flat)?
Flatten nested array bằng đệ quy reduce hoặc iterative spread. Phỏng vấn thường hỏi để test hiểu recursion và Array methods.
- Implement Promise.all từ đầu?
Promise.all resolve khi tất cả promises resolve; reject ngay khi có 1 promise reject. Lưu ý: handle empty array (resolve ngay []). Reject ngay khi 1 promise reject.
- Implement EventEmitter class đơn giản?
- Viết hook useLocalStorage trong React?
useLocalStorage persists state vào localStorage, tự đồng bộ khi value thay đổi. Test khả năng viết custom hooks với side effects.
- Implement infinite scroll hook?
useInfiniteScroll trigger callback khi sentinel element xuất hiện trong viewport. Gán ref cho sentinel element cuối danh sách.
- Viết hàm curry đa năng?
- Implement simple React context store (mini Redux)?
Mini Redux dùng Context + useReducer: store dùng chung cho toàn app mà không cần thư viện ngoài. Phỏng vấn thường hỏi để test hiểu state management internals.
- Viết hàm retry với exponential backoff?
Exponential backoff retry một async call failing với delay tăng dần (1s, 2s, 4s...). Dùng cho API calls không ổn định. Delay tăng: 1s, 2s, 4s.
- Implement simple virtual list (render chỉ visible items)?
- Viết function so sánh 2 objects deep equal?
Deep equal so sánh đệ quy toàn bộ nested values — không dùng được === cho objects. Phỏng vấn thường hỏi để test recursion và edge cases (null, arrays).
- Implement memoize function cho expensive computations?
Memoize caches kết quả function theo argument key, tránh tính toán lại những lần sau. Lưu ý: JSON.stringify chậm cho args lớn. Production dùng WeakMap cho object args, LRU cache giới hạn size.
- Implement simple pub/sub system cho micro-frontends?
- Viết middleware pipeline pattern (giống Express)?
- FizzBuzz coding challenge. Viết code, optimize, handle edge case.
FizzBuzz là bài toán kinh điển: lặp từ 1 đến n, in 'Fizz' nếu chia hết cho 3, 'Buzz' nếu chia hết cho 5, 'FizzBuzz' nếu chia hết cho cả hai, còn lại in số đó. Trường hợp biên cần xử lý: n bằng 0,…
- Implement simple LRU cache. Explain HashMap + LinkedList data structure.
LRU (Least Recently Used) Cache là cấu trúc dữ liệu loại bỏ phần tử ít được dùng gần đây nhất khi cache đầy. Trong JavaScript, Map vốn đã giữ thứ tự chèn, nên có thể dùng Map thay cho Doubly Linked List để triển khai…
- Array method efficiency. map vs forEach vs reduce performance?
forEach dùng để duyệt mảng và thực hiện side effect — không trả về mảng mới nên không tốn thêm bộ nhớ cấp phát. map tạo và trả về mảng mới cùng độ dài, tốn thêm bộ nhớ do phải cấp phát mảng — dùng…
- Memory leak trong JavaScript là gì và các nguyên nhân phổ biến?
- Object.groupBy() và Map.groupBy() (ES2024) là gì? Khi nào chọn cái nào?
Hai static method gom các phần tử của một iterable thành nhóm dựa trên giá trị callback trả về, thay cho việc tự viết reduce lồng nhau. - Object.groupBy(items, fn) → trả về object thường (null-prototype), key là string/symbol (giá trị callback bị ép về…
- Promise.withResolvers() (ES2024) giải quyết vấn đề gì so với new Promise()?
Promise.withResolvers() trả về một object gồm promise, resolve và reject cùng lúc, đưa hai hàm điều khiển ra ngoài phạm vi executor. Vấn đề với new Promise(executor): muốn resolve promise từ chỗ khác (event handler, callback của thư viện, hàng đợi message) bạn phải khai…
- Array.fromAsync() (ES2024) khác Array.from() và Promise.all() như thế nào?
Array.fromAsync() tạo một mảng từ async iterable (hoặc sync iterable chứa promise), trả về một Promise. - Lặp tuần tự và await từng phần tử — khác Promise.all() chạy song song. Hợp khi nguồn là stream/paginated và bạn muốn xử lý lần lượt. - Hỗ…
- Các Set method mới trong ES2025 (union, intersection, difference, isSubsetOf...) là gì? Có bẫy gì với argument?
ES2025 thêm các phép toán tập hợp ngay trên Set, thay cho việc tự convert sang array. - Trả về Set mới: union, intersection, difference, symmetricDifference. - Trả về boolean: isSubsetOf, isSupersetOf, isDisjointFrom. Lưu ý: argument không nhất thiết là Set thật — nó phải…
- structuredClone() là gì? Nó khác JSON.parse(JSON.stringify()) ở những điểm nào?
structuredClone(value) là hàm built-in deep-clone, dùng thuật toán structured clone của nền tảng (cùng cơ chế postMessage của Web Worker). Hơn JSON.parse(JSON.stringify(x)) ở chỗ: - Giữ được Date, RegExp, Map, Set, ArrayBuffer, TypedArray, Blob, File — JSON làm hỏng (Date thành string, Map thành {}).…
- WeakRef và FinalizationRegistry là gì? Tại sao tài liệu khuyên hạn chế dùng?
- Iterator helpers (map, filter, take, drop) trong ES2025 là gì? Ưu điểm lazy so với array method?
- Array.prototype.at(), findLast() và findLastIndex() làm được gì mà cách cũ khó hơn?
Ba method giúp truy cập từ cuối mảng sạch hơn. - at(index) hỗ trợ chỉ số âm: at(-1) là phần tử cuối. Cách cũ arr[arr.length - 1] dài dòng, và không gọn khi arr là biểu thức. - findLast(fn) / findLastIndex(fn) duyệt từ phải sang…
- RegExp flag /v (unicodeSets) trong ES2024 là gì? Hơn flag /u ở điểm nào?
- Top-level await trong ES modules là gì? Nó ảnh hưởng thế nào đến thứ tự load module?
- Generator và iterator trong JavaScript là gì?
- Đoạn code sau in ra thứ tự nào? Giải thích.
```js
setTimeout(() => console.log('timeout'), 0)
setImmediate(() => console.log('immediate'))
Promise.resolve().then(() => console.log('promise'))
process.nextTick(() => console.log('nextTick'))
console.log('sync')
```
Thứ tự: sync → nextTick → promise → sau đó timeout và immediate theo thứ tự không cố định. Vì sao: 1. console.log('sync') chạy đồng bộ trước hết. 2. Sau khi stack đồng bộ rỗng, Node xử lý nextTick queue trước, rồi mới tới microtask…
- Vì sao `setTimeout(fn, 0)` và `setImmediate(fn)` cho thứ tự không xác định ở main module, nhưng trong callback I/O thì `setImmediate` luôn chạy trước?
Vì hai hàm nằm ở hai phase khác nhau của event loop, và vị trí bạn gọi chúng quyết định phase nào đến trước. Một vòng lặp đi qua các phase theo thứ tự: timers → pending callbacks → poll → check → close callbacks.…
- Làm sao đo được event loop có đang bị chặn trong production? Chỉ số nào nên đưa lên dashboard?
- Vì sao đệ quy bằng `process.nextTick()` có thể làm chết ứng dụng, còn đệ quy bằng `setImmediate()` thì không?
- `[] + {}` và `{} + []` cho ra kết quả gì? Giải thích vì sao.
Trong ngữ cảnh biểu thức (gán vào biến, truyền vào hàm) cả hai đều ra '[object Object]'. Chỉ khi gõ trực tiếp {} + [] ở đầu một dòng lệnh (REPL/console) mới ra 0. Cơ chế: 1. Toán tử + khi có ít nhất một…
- Vì sao `0.1 + 0.2 !== 0.3`? Trong hệ thống có tiền tệ bạn xử lý thế nào?
Số trong JavaScript là IEEE-754 double (nhị phân 64-bit). Các phân số như 0.1, 0.2 không biểu diễn chính xác được ở hệ nhị phân nên bị làm tròn, cộng vào ra 0.30000000000000004. Với tiền tệ, không dùng float. Ba cách phổ biến: - Lưu…
- Dùng object thường làm cache với key là object thì có vấn đề gì? Khi nào phải dùng `Map`?
Key của object thường luôn bị ép về chuỗi (hoặc Symbol). Mọi object dùng làm key đều thành '[object Object]', nên các entry khác nhau ghi đè lẫn nhau. Dùng Map khi: - Key không phải chuỗi (object, số, hàm) — Map so khớp key…
- `delete obj.x` khác `obj.x = undefined` thế nào?
delete gỡ hẳn property khỏi object; gán undefined giữ property lại nhưng đổi giá trị. Khác biệt lộ ra ở mọi thao tác duyệt hoặc kiểm tra sự tồn tại. Hai điểm hay bị hỏi thêm: - delete trả về true cả khi property không…
- `Object.freeze` có làm object bất biến hoàn toàn không? Muốn đóng băng sâu thì làm sao?
Không. Object.freeze chỉ đóng băng nông (shallow): nó chặn thêm/xoá/sửa property ở tầng đầu tiên, nhưng object lồng bên trong vẫn sửa được vì frozen chỉ khoá tham chiếu, không khoá thứ mà tham chiếu trỏ tới. Deep freeze phải duyệt đệ quy: Lưu ý…
- Vì sao `const fn = obj.method; fn()` lại mất `this`? Có mấy cách sửa?
Vì this trong JavaScript được quyết định lúc gọi hàm, không phải lúc định nghĩa. Khi gán method ra biến, bạn chỉ lấy tham chiếu tới hàm, phần "chủ thể gọi" (obj.) không đi kèm. Gọi fn() không kèm object thì this là undefined ở…
- Viết `const limit = input.limit || 20` gây bug gì? `??` khác `||` chỗ nào?
Bug xảy ra khi giá trị hợp lệ lại là falsy. trả về vế phải với mọi falsy: 0, '', false, NaN, null, undefined. Còn ?? chỉ trả vế phải khi vế trái là null hoặc undefined. Trường hợp thực tế hay dính: cờ bật/tắt…
- API trả về `{ name: null }` mà `const { name = 'Khách' } = user` vẫn ra `null`. Vì sao? Cách đổi tên biến khi destructure?
Giá trị mặc định trong destructuring chỉ kích hoạt khi giá trị là undefined, không kích hoạt với null. null là một giá trị hợp lệ nên nó được gán thẳng. Cách xử lý null từ API: destructure rồi lọc riêng, hoặc dùng ?? sau…
- Vòng lặp `for (var i = 0; i < 3; i++) setTimeout(() => console.log(i))` in ra gì? Đổi `var` thành `let` thì sao?
Với var in ra 3 3 3. Với let in ra 0 1 2. var có phạm vi function, nên cả ba callback đều capture cùng một biến i. Khi timer chạy (sau khi vòng lặp kết thúc), i đã là 3. let có phạm…
- `let`/`const`/`class` có được hoisting không? TDZ là gì?
Có hoisting — binding được tạo ngay đầu block — nhưng chưa được khởi tạo. Khoảng từ đầu block tới dòng khai báo gọi là TDZ (Temporal Dead Zone); truy cập trong khoảng này ném ReferenceError. Điểm phân biệt quan trọng: undefined nghĩa là "biến…
- Spread `{...obj}` và `Object.assign` có copy sâu không? Muốn copy sâu thì dùng gì?
Cả hai đều copy nông (shallow): chỉ sao chép các thuộc tính own enumerable ở tầng một. Object lồng bên trong vẫn dùng chung tham chiếu. Đây là nguyên nhân gây bug thường gặp trong React/Redux: tưởng đã tạo state mới nhưng object con vẫn…
- `__proto__` khác `prototype` thế nào? `class` và `Object.create` tạo ra chuỗi prototype giống nhau không?
- `call`, `apply`, `bind` khác nhau ra sao? `bind` hai lần thì `this` là của lần nào?
- Làm sao để một object tự viết dùng được với `for...of` và spread? Iterator protocol hoạt động thế nào?
- `Object.defineProperty` cho kiểm soát thêm những gì so với gán thường? Vì sao Proxy thay thế được nó?
- JavaScript có garbage collector rồi thì memory leak xảy ra kiểu gì? Kể vài nguồn rò rỉ hay gặp trên web.
- Đoạn code sau in ra thứ tự nào? Giải thích tại sao.
Kết quả: 1, 4, 3, 2. - 1 và 4 là code đồng bộ, chạy hết trước mọi thứ khác. - 3 nằm trong microtask queue (callback của Promise). Microtask được chạy hết ngay sau khi call stack rỗng, trước khi event loop nhận task…
- Tại sao `async function` luôn trả về Promise? Gọi nó mà không `await` thì chuyện gì xảy ra?
Đặc tả quy định async function luôn bọc giá trị trả về vào một Promise. return 1 cho ra Promise đã fulfilled với giá trị 1; throw err cho ra Promise đã rejected chứ không ném đồng bộ. Nếu bên trong return một Promise, kết…
- Tại sao `array.forEach(async (item) => await save(item))` không chờ xong? Sửa thế nào?
Vì forEach bỏ qua giá trị trả về của callback. Callback async trả về một Promise, forEach vứt đi và chạy tiếp phần tử kế — nên vòng lặp kết thúc ngay lập tức trong khi các save() vẫn đang chạy. Hai cách sửa, chọn…
- Tại sao `try/catch` không bắt được lỗi ném bên trong callback của `setTimeout`?
Vì lúc callback chạy, khối try đã kết thúc từ lâu. try/catch chỉ bảo vệ những gì thực thi trên cùng call stack đồng bộ với nó. setTimeout chỉ đăng ký callback rồi trả về ngay; try thoát, stack rỗng. Sau đó event loop lấy…
- Trang dashboard gọi 5 API độc lập, một API chậm hoặc lỗi. Bạn chọn `Promise.all`, `allSettled`, `race` hay `any`? Vì sao?
Với dashboard, câu trả lời gần như luôn là Promise.allSettled: mỗi widget hiển thị độc lập, một API lỗi không nên xoá trắng cả trang. Chọn theo ngữ nghĩa: - all — fail-fast, reject ngay khi một cái lỗi. Dùng khi thiếu bất kỳ mảnh…
- Khi nào bắt buộc gọi API tuần tự (`for await`) và khi nào nên song song (`Promise.all`)? Sai chỗ này ảnh hưởng gì?
Nguyên tắc: song song mặc định, tuần tự khi có ràng buộc. Bắt buộc tuần tự khi: - Request sau cần kết quả của request trước (lấy token rồi mới gọi API; lấy nextCursor để phân trang). - Thao tác ghi phải đúng thứ tự…
- `fetch` không có timeout mặc định. Bạn đặt timeout và huỷ request thế nào?
Dùng AbortController — cách duy nhất huỷ được fetch đang chạy. Bản ngắn gọn là AbortSignal.timeout(): Khi cần huỷ thủ công (user rời trang, gõ query mới) thì tự quản controller: Cần vừa timeout vừa huỷ tay thì gộp signal bằng AbortSignal.any([controller.signal, AbortSignal.timeout(5000)]). Các điểm…
- Cài retry với exponential backoff ở phía client thế nào? Request nào được phép retry?
Backoff nghĩa là mỗi lần thử lại chờ lâu hơn theo cấp số nhân, cộng thêm jitter ngẫu nhiên để nhiều client không cùng bắn lại một thời điểm. Chỉ retry khi an toàn: - Lỗi mạng, timeout, 429, 503, 502 — tạm thời. -…
- Ô search gõ nhanh: kết quả của từ khoá cũ về sau và đè lên kết quả mới. Xử lý thế nào?
Đây là stale response — nhiều request cùng bay, thứ tự phản hồi không đảm bảo theo thứ tự gửi. Request cho "ipho" có thể về sau request cho "iphone" và ghi đè state. Ba cách xử lý, xếp theo mức độ nên dùng: 1.…
- Debounce một hàm **async** có gì khác so với hàm đồng bộ? Chỗ nào dễ sai?
Debounce chuẩn chỉ hoãn thời điểm gọi; nó không biết gì về Promise. Ba vấn đề phát sinh khi hàm bên trong là async: 1. Mất giá trị trả về. debounce(fn) trả undefined, nên await debouncedSearch(term) vô nghĩa. Muốn await được thì bản debounce phải…
- `return await promise` và `return promise` khác nhau ra sao? Khi nào bắt buộc dùng `return await`?
Về giá trị cuối thì giống nhau — cả hai đều cho ra cùng kết quả cho người gọi. Khác biệt nằm ở try/catch và stack trace. Với return promise, hàm thoát khỏi khối try ngay lập tức rồi mới trả promise ra ngoài; lúc…
- Có 500 file cần upload nhưng chỉ được chạy tối đa 5 request cùng lúc. Cài đặt thế nào?
- Một Promise reject mà không ai `.catch()` thì chuyện gì xảy ra? Vì sao `Promise.all` dễ tạo ra tình huống này?
- Trong một vòng event loop, thứ tự giữa microtask, `requestAnimationFrame` và `setTimeout` là gì? Render chen vào chỗ nào?
- Async generator và `for await...of` giải quyết bài toán gì? Cho ví dụ đọc API phân trang.
- Tại sao `async/await` không làm code chạy song song? Khi nào bắt buộc phải dùng Web Worker?
- Trình duyệt đi từ HTML tới pixel trên màn hình qua những bước nào (critical rendering path)?
Trình duyệt chạy qua 5 bước cố định: 1. Parse HTML → DOM: đọc byte HTML thành cây node. 2. Parse CSS → CSSOM: mọi stylesheet được tải và parse thành cây style. 3. Render tree: ghép DOM + CSSOM, bỏ node không hiển thị…
- Cookie, localStorage, sessionStorage và IndexedDB khác nhau thế nào? Khi nào chọn cái nào?
Khác nhau ở dung lượng, vòng đời, và có tự gửi lên server hay không. - Cookie — ~4KB mỗi cookie, tự động đính kèm mọi request cùng origin (kể cả ảnh, API). Có Expires, và quan trọng là có HttpOnly để JS không đọc…
- Sự kiện DOM lan truyền thế nào (capturing và bubbling)? Event delegation là gì?
Một sự kiện đi qua 3 pha: capturing (từ window đi xuống phần tử đích), target (tại chính phần tử), rồi bubbling (nổi ngược lên window). Mặc định addEventListener nghe ở pha bubbling; truyền { capture: true } để nghe ở pha đi xuống. Event…
- Các thuộc tính `HttpOnly`, `Secure`, `SameSite` của cookie có tác dụng gì? Đặt thế nào cho cookie phiên đăng nhập?
Ba thuộc tính này chặn ba loại tấn công khác nhau: - HttpOnly — JS (document.cookie) không đọc được cookie. Đây là lớp phòng thủ chính khi trang dính XSS: script chèn vào cũng không lấy được session. - Secure — cookie chỉ gửi qua…
- Vòng đời của service worker gồm những giai đoạn nào? Vì sao deploy bản mới mà người dùng vẫn thấy bản cũ?
Service worker đi qua: register → install → (waiting) → activate → idle/terminated. - install: chạy một lần cho mỗi phiên bản script, thường dùng để precache asset. - waiting: nếu đã có service worker cũ đang điều khiển trang, bản mới đứng chờ —…
- Triển khai infinite scroll bằng `IntersectionObserver` thế nào? `root`, `rootMargin`, `threshold` ảnh hưởng ra sao và có bẫy gì?
- Có những chiến lược cache nào trong service worker? Chọn chiến lược nào cho HTML, cho asset có hash, và cho API?
- Đồng bộ trạng thái giữa nhiều tab (vd đăng xuất một tab thì các tab khác cũng thoát) làm thế nào?
- Cookie `Partitioned` (CHIPS) là gì? Việc siết cookie bên thứ ba ảnh hưởng thế nào tới SSO và widget nhúng?
- Bạn thiết kế luồng đăng nhập lưu token và tự refresh khi hết hạn thế nào?
- Upload ảnh có preview và nén phía client trước khi gửi — bạn làm thế nào?
Ba bước: preview ngay, nén trước khi gửi, giải phóng tài nguyên. Preview dùng URL.createObjectURL(file) — nhanh hơn FileReader.readAsDataURL vì không phải mã hoá base64 toàn bộ file vào chuỗi. Bắt buộc revokeObjectURL khi bỏ ảnh hoặc unmount, nếu không blob sẽ nằm lại trong…
- Dark mode bị nháy trắng một nhịp khi tải trang (FOUC) — nguyên nhân và cách xử lý?
Nguyên nhân: trình duyệt vẽ trang bằng theme mặc định trước, mãi tới khi JavaScript của app chạy xong (đọc localStorage, set state) mới đổi sang dark. Khoảng giữa hai mốc đó chính là nhịp nháy trắng. Cách xử lý là quyết định theme trước…
- Hiển thị tiền VND và ngày giờ theo chuẩn Việt Nam thế nào cho đúng?
Dùng Intl thay vì tự viết hàm chèn dấu chấm và ghép chuỗi ngày. Những chi tiết hay bị hỏi tiếp: - VND không có phần thập phân — Intl tự biết điều đó, còn hàm tự viết thường in ra ".00" thừa. - Định…
- Người dùng mất mạng giữa chừng thì frontend nên xử lý thế nào?
Hai việc: cho người dùng biết và tự phục hồi khi mạng trở lại. Phát hiện. navigator.onLine cùng sự kiện online / offline cho biết máy có kết nối mạng hay không: Lưu ý giới hạn: onLine === true chỉ nghĩa là máy có kết…
- Trang hiển thị bình luận do người dùng nhập — bạn chống XSS thế nào?