Tổng hợp 106 câu hỏi phỏng vấn Frontend Essentials kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
DOCTYPE (Document Type Declaration) khai báo phiên bản HTML đang dùng và phải nằm ở dòng đầu tiên. HTML5 chỉ cần một dòng: Nó quyết định browser render ở standards mode hay quirks mode. Thiếu DOCTYPE → quirks mode, và khác biệt lớn nhất là…
Semantic HTML là dùng thẻ mô tả đúng vai trò nội dung thay vì <div/<span trung tính. Bốn lý do nó đáng giá: 1. Accessibility — screen reader nhảy thẳng tới landmark (main, nav, header); với <div thì không có gì để nhảy tới. 2.…
Sự khác biệt chính bao gồm: - Kiến trúc (Architecture): App Router (Next.js 13+) dùng thư mục app/ và hỗ trợ React Server Components mặc định. Pages Router dùng thư mục pages/ nơi mọi component được xử lý như Client Component. - Data Fetching: App…
Server Component khi cần: data fetching, access backend resources, keep sensitive info (API keys), reduce client bundle. Client Component khi cần: onClick, onChange event handlers, useState/useEffect, browser APIs, real-time updates, custom hooks. Default là Server, chỉ dùng 'use client' khi thực sự cần interactivity.
next/image tự động: resize và optimize images theo viewport, serve WebP/AVIF modern formats, lazy load mặc định, prevent Cumulative Layout Shift (CLS) với width/height hoặc fill. Cần cung cấp width và height hoặc fill prop. Cấu hình allowed domains trong next.config. Tích hợp CDN support…
SEO (Search Engine Optimization) là tối ưu hoá website để đạt thứ hạng cao trên Google, Bing, và các công cụ tìm kiếm. 68% online experiences bắt đầu từ search engine — frontend developer ảnh hưởng trực tiếp đến khả năng index và rank của…
Có 5 meta tags quan trọng nhất mà frontend dev cần nắm: title, description, robots, canonical, và Open Graph. Title tag (<title): quan trọng nhất, hiển thị trên tab browser và kết quả tìm kiếm. Quy tắc: 50-60 ký tự, chứa keyword chính ở đầu,…
Rendering strategy là yếu tố critical ảnh hưởng khả năng Google index content — CSR là rủi ro cao nhất, SSR/SSG an toàn nhất. CSR (Client-Side Rendering): HTML ban đầu trống, JS render content → Google phải chờ JS execute (second wave indexing). Rủi ro:…
Core Web Vitals (CWV) là 3 metrics đo trải nghiệm người dùng, là ranking signal của Google từ 2021. INP thay thế FID từ tháng 3/2024. LCP (Largest Contentful Paint): thời gian render phần tử lớn nhất (hero image, heading) — target: <2.5s. Cải thiện:…
Amend last commit — chỉ dùng khi commit CHƯA push: Nếu đã push (chỉ branch của riêng bạn): Lưu ý: - --amend tạo commit MỚI với hash khác — không phải edit in-place - KHÔNG amend commits trên main/develop hoặc bất kỳ shared branch -…
Merge: tạo merge commit, preserve history đầy đủ. git log --graph thấy nhánh. Non-destructive — không thay đổi existing commits. Rebase: replay commits lên trên branch khác, tạo linear history. Rewrite commit hashes. Golden Rule of Rebasing: KHÔNG BAO GIỜ rebase branch đã được share/push…
Worst case conflict: không phải thêm/xoá dòng đơn giản mà là structural refactor — function bị rename, logic được reorganize. Quy trình an toàn: 1. Hiểu context trước khi resolve: 2. Dùng 3-panel merge tool — git mergetool (trái: ours, phải: theirs, giữa: base —…
Reset (git reset --hard HEAD~1): di chuyển HEAD pointer về commit cũ, xoá commits khỏi history. KHÔNG dùng trên main/shared branch — sẽ cần force push, làm hỏng history của mọi người đã pull. Revert (git revert <commit): tạo commit MỚI undo changes của commit…
Access token có hạn ngắn; khi nó hết hạn, client dùng refresh token (hạn dài hơn) gọi endpoint /token để lấy access token mới — không bắt người dùng đăng nhập lại. Đó là "silent refresh". Refresh token rotation: mỗi lần refresh, server cấp refresh…
XSS (Cross-Site Scripting) = chèn mã JS độc vào trang, chạy trong phiên của nạn nhân → đánh cắp token/cookie, mạo danh, đọc dữ liệu. Ba loại: stored, reflected, DOM-based. Phòng chống: - Output encoding theo ngữ cảnh (HTML, attribute, JS, URL). - Framework tự…
Same-Origin Policy chặn fetch/XHR đọc dữ liệu cross-origin; CORS là cơ chế server dùng HTTP header để cho phép origin khác đọc. - Simple request (GET/HEAD/POST + Content-Type safelisted): không có preflight. - Preflighted: khi dùng method khác, custom header, hoặc Content-Type: application/json → trình…
Origin = scheme + host + port; hai URL cùng origin khi cả ba khớp (khác scheme http/https, khác port, hay khác subdomain đều là cross-origin). SOP hạn chế tương tác cross-origin: - Đọc cross-origin (fetch/XHR đọc nội dung response) → chặn mặc định, muốn…
Session: server lưu trạng thái phiên trong store; client chỉ giữ session id trong cookie; mỗi request server tra store để xác thực. → Thu hồi tức thì, nhưng stateful (cần shared store khi scale nhiều instance). Token (JWT): server ký token chứa claim, client…
JWT (RFC 7519) gồm 3 phần ngăn bởi dấu chấm: header.payload.signature, mỗi phần encode bằng Base64URL. - Header: loại token + thuật toán ký (vd HS256). - Payload: các claim — thông tin về chủ thể + metadata. - Signature: ký header+payload bằng HMAC/RSA/ECDSA với…
- <script thường: tải rồi chạy ngay, chặn việc parse HTML; nhiều script chạy đúng thứ tự. - async: tải song song trong khi parse HTML, chạy ngay khi tải xong (có thể chen giữa lúc render), KHÔNG đảm bảo thứ tự giữa các script.…
Tree-shaking = loại bỏ code chết (dead-code elimination): bundler bỏ các export không được import ra khỏi bundle production. Nó dựa vào cấu trúc tĩnh của ES module — import/export phân tích được lúc build. Vì vậy không được để Babel transpile ESM sang CommonJS…
Closure = một hàm giữ tham chiếu tới scope nơi nó được khai báo, nên vẫn đọc/ghi được biến của scope cha ngay cả khi hàm cha đã chạy xong. Nói cách khác, hàm "nhớ" môi trường tạo ra nó. - Nền tảng của closure…
this phụ thuộc cách hàm được gọi, không phải nơi định nghĩa (trừ arrow function). Thứ tự ưu tiên: 1. new → this là object mới tạo. 2. call/apply/bind → this là giá trị truyền vào. 3. Method call obj.fn() → this là obj. 4.…
Hoisting: khai báo được "nâng" lên đầu scope lúc biên dịch. Nhưng cách khởi tạo khác nhau: var let / const --------- Scope function block {} Hoist có, khởi tạo undefined có, nhưng TDZ Truy cập trước khai báo undefined ReferenceError Gán lại được let…
Mỗi object có một liên kết ẩn [[Prototype]] (đọc qua Object.getPrototypeOf, hoặc proto) trỏ tới object khác. Khi truy cập một property mà object không có, engine đi ngược lên chuỗi prototype cho tới khi tìm thấy hoặc chạm null. Đó là prototype chain. -…
- === (strict): so sánh cả kiểu và giá trị, không ép kiểu. 1 === '1' → false. - == (loose): ép kiểu hai vế về cùng dạng rồi mới so sánh, dẫn tới nhiều kết quả khó đoán. Vài ca == gây bất ngờ:…
Callback: truyền hàm để gọi khi xong. Lồng nhiều callback bất đồng bộ → "callback hell": khó đọc, khó xử lý lỗi, đảo ngược quyền kiểm soát (inversion of control). Promise: object đại diện cho kết quả tương lai, có 3 trạng thái pending →…
Một sự kiện DOM lan theo 3 pha: capturing (từ document đi xuống target) → target → bubbling (từ target đi ngược lên). Mặc định addEventListener nghe ở pha bubbling; truyền { capture: true } để nghe ở pha capturing. - event.target = phần tử…
Cả hai giới hạn tần suất chạy một hàm bị kích hoạt liên tục, nhưng theo cách khác nhau: - Debounce: gom nhiều lần gọi thành một — chỉ chạy sau khi ngừng kích hoạt một khoảng wait. Mỗi lần gọi mới sẽ reset đồng…
- Destructuring: rút giá trị từ mảng/object ra biến. - const [a, b] = arr, const { x, y } = obj. - Đổi tên { x: newX }, mặc định { x = 0 }, lồng nhau, dùng cho tham số hàm. - Spread…
Cả ba không mutate mảng gốc, trả về giá trị mới, hợp phong cách khai báo: - map: biến đổi từng phần tử, trả mảng cùng độ dài. [1,2,3].map(x = x 2) → [2,4,6]. - filter: giữ phần tử thoả điều kiện, trả mảng ngắn…
Object/array là kiểu tham chiếu; gán b = a chỉ chép tham chiếu, sửa b là sửa luôn a. - Shallow copy: sao chép một cấp; property lồng bên trong vẫn dùng chung tham chiếu. - Cách: { ...obj }, Object.assign({}, obj), arr.slice(), [...arr]. -…
Cả ba lưu dữ liệu ở client nhưng khác nhau rõ: Cookie localStorage sessionStorage ------------ Dung lượng ~4KB ~5–10MB ~5–10MB Gửi kèm request Có (mỗi HTTP request) Không Không Vòng đời theo Expires/Max-Age tới khi bị xoá hết khi đóng tab Phạm vi theo domain/path…
Mỗi phần tử là một hộp gồm 4 lớp từ trong ra ngoài: content → padding → border → margin. - Mặc định content-box: width/height chỉ tính phần content; padding và border cộng thêm vào kích thước hiển thị. Đặt width: 200px; padding: 20px; border:…
Khi nhiều rule cùng nhắm một phần tử, trình duyệt chọn rule có specificity cao nhất. Tính theo bộ ba (A, B, C): - A — số ID selector (id). - B — số class, attribute, pseudo-class (.x, [type], :hover). - C — số element…
- Flexbox = layout một chiều (hàng hoặc cột). Phân bổ không gian dọc theo một trục; hợp khi số item động và bạn muốn chúng tự co giãn/xuống dòng. - Trục chính: flex-direction, justify-content (căn theo trục chính), align-items (căn theo trục phụ), gap,…
- static (mặc định): theo luồng bình thường; top/left/z-index không có tác dụng. - relative: vẫn giữ chỗ trong luồng nhưng dịch chuyển theo top/left… so với vị trí gốc của chính nó. Thường dùng để làm mốc cho con absolute. - absolute: thoát khỏi…
Cả hai là đơn vị tương đối theo font-size, nhưng lấy mốc khác nhau: - rem (root em): luôn tính theo font-size của phần tử gốc <html. Một mốc duy nhất → nhất quán, dễ đoán, không bị dồn tầng. - em: với thuộc tính…
Virtual DOM (VDOM): bản mô tả UI bằng object JS nhẹ, phản chiếu cây DOM thật. Thao tác trên object rẻ hơn nhiều so với thao tác trực tiếp trên DOM thật. Khi state/props đổi, React: 1. Tạo cây VDOM mới cho lần render. 2.…
key giúp React nhận diện ổn định mỗi phần tử trong danh sách qua các lần render. Nhờ đó khi diff, React biết phần tử nào được giữ, thêm, xoá, hay đổi chỗ thay vì dựng lại toàn bộ. Vì sao không nên dùng array…
Rules of Hooks (bắt buộc để React khớp đúng state qua các lần render): 1. Chỉ gọi hook ở cấp cao nhất — không đặt trong if, vòng lặp, hàm lồng. React nhận diện hook theo thứ tự gọi, nên thứ tự phải ổn định.…
Phân biệt theo nơi giữ giá trị của form input: - Controlled: React state là single source of truth. Input nhận value={state} và cập nhật qua onChange. React kiểm soát mọi lần gõ. - Ưu: dễ validate tức thời, disable nút, format khi gõ, đồng…
Bốn cách này khác nhau ở chỗ HTML được dựng ở đâu và vào lúc nào. CSR dựng trên trình duyệt, SSR dựng trên server ở mỗi request, SSG dựng một lần lúc build, còn ISR giống SSG nhưng tự dựng lại trang sau một…
Cả hai đều mô tả shape của object và phần lớn thay thế được cho nhau. Khác biệt cốt lõi: - interface: mở rộng bằng extends, và có declaration merging — khai báo trùng tên sẽ gộp lại. Hợp public API của thư viện, mô…
Generic = tham số hoá kiểu: viết hàm/class/type hoạt động trên nhiều kiểu mà vẫn giữ quan hệ giữa các kiểu. - function identity<T(x: T): T — T được suy ra từ đối số truyền vào, giá trị trả về giữ đúng kiểu đó. -…
TypeScript có sẵn các type biến đổi một type gốc, giúp dẫn xuất thay vì khai báo lại (DRY): - Partial<T — mọi field thành optional (hợp payload update/patch). - Required<T — mọi field thành bắt buộc. - Pick<T, K — lấy ra một tập…
- React.lazy(() = import('./X')) khai báo một component nạp động: bundler tách nó thành chunk riêng, chỉ tải khi component thực sự render → code splitting. - <Suspense fallback={...} bọc component lazy (hoặc component đọc dữ liệu qua data lib hỗ trợ Suspense) và hiển…
Error boundary = một class component cài static getDerivedStateFromError() và/hoặc componentDidCatch(), nó bắt lỗi render của cây con rồi hiện UI dự phòng thay vì làm sập cả app (màn trắng). Bắt được: lỗi khi render, trong lifecycle, và constructor của các component con. KHÔNG…
Context truyền dữ liệu xuyên cây component mà không phải chuyền prop qua từng tầng (prop drilling): createContext → <Provider value → useContext. Lưu ý quan trọng: Context không phải state manager. Mọi consumer sẽ re-render khi value đổi (dù chỉ dùng một phần nhỏ)…
Ảnh thường là phần nặng nhất của trang, nên tối ưu: - Lazy-load ảnh ngoài viewport: <img loading="lazy" — hoãn tải tới khi gần cuộn đến. - Responsive images: srcset + sizes để trình duyệt tự chọn kích thước hợp với DPR/viewport → không tải…
Thay vì gửi một bundle to cho toàn app, code splitting chia thành nhiều chunk tải theo nhu cầu → giảm JS phải parse/execute ban đầu, cải thiện thời gian tương tác (TTI). - import('./mod') động trả về Promise; bundler (webpack/Vite) tự tách một chunk…
- CommonJS (Node.js truyền thống): require() / module.exports, nạp đồng bộ lúc runtime, và động (có thể require trong if). Cấu trúc module không phân tích tĩnh được hoàn toàn. - ES Modules (chuẩn ngôn ngữ): import / export, cấu trúc tĩnh — phân tích…
Memoization = lưu lại kết quả theo input: khi input lặp lại, trả kết quả đã tính thay vì tính lại. Trong React có ba công cụ: - useMemo(fn, deps): nhớ giá trị của một phép tính nặng; chỉ tính lại khi deps đổi. -…
JavaScript có 7 kiểu primitive (string, number, boolean, undefined, null, symbol, bigint) và kiểu reference — object, array, function. - Copy: gán primitive sang biến khác là sao chép giá trị — hai biến độc lập. Gán object chỉ sao chép tham chiếu — hai…
Arrow function không chỉ là cú pháp ngắn — nó khác function thường ở bốn điểm: - this: arrow không có this riêng — nó lấy this từ scope bao quanh lúc định nghĩa (lexical) và không đổi được bằng call/apply/bind. Function thường có this…
Cả ba đều làm element "biến mất" nhưng khác nhau về layout, tương tác và a11y: - display: none: gỡ element khỏi layout — không chiếm chỗ, không render, con cháu ẩn theo và không ghi đè lại được. Bị loại khỏi accessibility tree (screen…
Responsive design = một codebase hiển thị tốt trên mọi kích thước màn hình, thay vì làm site riêng cho mobile. Ba mảnh ghép chính: - Viewport meta: <meta name="viewport" content="width=device-width, initial-scale=1" — bảo trình duyệt mobile render theo bề rộng thật của thiết bị…
Cả hai đều là script chạy trên thread riêng, tách khỏi main thread và không truy cập được DOM — nhưng vai trò khác hẳn: - Web Worker: thread tính toán cho một trang. Dùng để đẩy việc nặng CPU (parse file lớn, xử lý…
fetch là API chuẩn hiện đại thay cho XHR: - Trả về Promise → dùng thẳng với async/await thay vì callback onreadystatechange. - API sạch hơn với object Request/Response, hỗ trợ streaming body, và là API duy nhất dùng được trong Service Worker. - Điểm…
Trình duyệt cache response theo header từ server, giúp lần truy cập sau không phải tải lại asset: - Cache-Control: max-age=N — response còn "tươi" trong N giây; trong khoảng đó trình duyệt dùng bản cache không hỏi server (nhanh nhất). Thêm immutable để báo…
- SPA (Single-Page Application): server trả về một trang HTML ban đầu, sau đó JavaScript đảm nhận toàn bộ — chuyển "trang" bằng client-side routing (đổi URL qua History API, render view mới) không reload trình duyệt. React/Vue/Angular là công cụ dựng SPA điển hình.…
Một component render lại khi: - State của chính nó đổi (setState/useState/useReducer). - Cha render lại — mặc định React render toàn bộ cây con, bất kể props có đổi hay không. Điểm hay hiểu nhầm: "props đổi" không phải trigger độc lập — con…
Cả hai đều biểu thị "không có giá trị" nhưng khác nhau về ý nghĩa và nguồn gốc: - undefined: biến đã khai báo nhưng chưa gán, tham số hàm thiếu, property không tồn tại, hàm không return — do engine tự đặt. Đây là…
Khi một giá trị được dùng ở ngữ cảnh boolean (if, !, &&, , toán tử ba ngôi), JS ép nó về true hoặc false. Giá trị ép thành false gọi là falsy, còn lại là truthy. Chỉ có 8 giá trị falsy (nhớ hết…
Ba giá trị display này quyết định phần tử tham gia luồng layout thế nào: block inline inline-block ------------ Xuống dòng mới Có (chiếm cả hàng) Không (nằm cùng dòng) Không (cùng dòng) width/height Có tác dụng Bị bỏ qua Có tác dụng margin/padding dọc…
Cả hai đều là dữ liệu điều khiển những gì component render, nhưng khác nhau về quyền sở hữu và khả năng thay đổi: - Props (properties): dữ liệu cha truyền xuống con. Với chính component nhận, props là chỉ đọc (read-only) — không được…
HTTP method báo mục đích của request: - GET — lấy dữ liệu, không có body, an toàn (không đổi trạng thái) và idempotent; có thể cache. - POST — tạo mới / gửi dữ liệu; không idempotent (gọi 2 lần tạo 2 bản ghi).…
- Optional chaining ?.: truy cập property/gọi method lồng sâu mà không lỗi khi gặp null/undefined. user?.address?.city — nếu user hoặc address là null/undefined thì trả về undefined thay vì ném TypeError. Dùng được với property (a?.b), index (a?.[i]), và gọi hàm (fn?.()). Nó short-circuit:…
Map — tập cặp key–value, thay cho việc dùng object làm dictionary: - Key bất kỳ kiểu (object, function, số...), không như object (key luôn ép về string/symbol). - Giữ đúng thứ tự chèn khi duyệt. - Có .size, và các method set/get/has/delete; duyệt trực…
Bốn combinator nhận một mảng promise, khác nhau ở điều kiện settle: - Promise.all: chờ tất cả fulfilled → trả mảng kết quả theo đúng thứ tự. Fail-fast: chỉ một promise reject là reject ngay với lỗi đó (không chờ số còn lại). Dùng khi…
0.1 + 0.2 → 0.30000000000000004: JS chỉ có một kiểu số — IEEE 754 double (64-bit floating point). Các phân số như 0.1, 0.2 không biểu diễn chính xác ở hệ nhị phân (giống 1/3 không hết ở hệ thập phân), nên phép cộng tích…
useRef trả về một object { current } ổn định qua mọi lần render (cùng một tham chiếu). Sửa ref.current không kích hoạt re-render. Hai công dụng chính: 1. Tham chiếu tới DOM node: gắn ref={myRef} vào JSX rồi thao tác trực tiếp — inputRef.current.focus(),…
Cả hai đều quản lý state trong component; useReducer là dạng tổng quát hơn cho logic cập nhật phức tạp. - useState: cập nhật trực tiếp bằng setter — hợp state đơn giản, độc lập (một cờ boolean, một chuỗi input). - useReducer(reducer, initialState): gom…
IntersectionObserver là API trình duyệt theo dõi bất đồng bộ khi một phần tử giao (intersect) với viewport (hoặc một phần tử cha cuộn được), rồi gọi callback khi mức hiển thị vượt các ngưỡng (threshold) ta đặt. Vì sao hơn nghe scroll + getBoundingClientRect():…
Một view fetch dữ liệu có bốn trạng thái, không phải một, và tôi thiết kế cả bốn ngay từ đầu: loading, error, empty (thành công nhưng không có dữ liệu), và success có dữ liệu. Bỏ sót empty là lỗi hay gặp — danh…
Vì state trong React là snapshot của lần render hiện tại: setState không sửa biến ngay mà yêu cầu một lần render mới; mọi dòng code phía sau trong cùng handler vẫn đọc giá trị của snapshot cũ. Batching: React gom nhiều lần setState trong…
Redux là một store toàn cục với luồng dữ liệu một chiều (one-way data flow): 1. UI dispatch một action — plain object mô tả "chuyện gì vừa xảy ra": { type: 'cart/itemAdded', payload: item }. 2. Action đi qua middleware (nếu có) — nơi…
Core Web Vitals là ba chỉ số Google dùng đánh giá trải nghiệm trang (và là tín hiệu xếp hạng tìm kiếm), tính trên người dùng thật tại percentile 75: - LCP (Largest Contentful Paint) — tốc độ tải: thời điểm phần tử nội dung…
Các cách chính, xếp theo mức nên dùng hiện nay: 1. Flexbox — mặc định cho hầu hết trường hợp: 2. Grid — ngắn nhất: 3. position: absolute + translate — khi phần tử tách khỏi luồng (overlay, modal): Dùng translate(-50%) thay vì margin âm…
CSRF (Cross-Site Request Forgery) lợi dụng việc trình duyệt tự động gửi cookie theo mọi request tới một site. Kẻ tấn công dụ user đã đăng nhập truy cập trang độc hại; trang đó âm thầm gửi request tới site nạn nhân (vd form chuyển…
Hai thứ giải quyết hai bài toán khác nhau. Server Action — mutation phát sinh từ chính UI của app: - Gắn thẳng vào <form action={...} hoặc gọi từ client component, không phải tự viết fetch và endpoint. - Chạy được cả khi JS chưa…
Next.js chia biến môi trường làm hai nhóm rất rõ: - Không có tiền tố (DATABASEURL, STRIPESECRETKEY): chỉ tồn tại ở phía server — Server Component, Route Handler, Server Action. Đọc ở client sẽ ra undefined. - Có NEXTPUBLIC (NEXTPUBLICGAID): được thay thế thẳng vào…
Lỗi xảy ra vì Next.js render component đó trên server (Node), nơi không có window/document. Thư viện chart, editor, map thường chạm vào DOM ngay khi import. ssr: false bảo Next.js bỏ qua component này trong lần render server, chỉ mount ở client. Kèm theo…