Blogs
Câu hỏi phỏng vấn JavaScript cho Junior

Câu hỏi phỏng vấn JavaScript cho Junior

Tuyển tập các câu hỏi phỏng vấn JavaScript cơ bản dành cho Junior, kèm giải thích dễ hiểu và ví dụ minh hoạ.


Q: Callback hell là gì?
A: Callback hell xảy ra khi bạn lồng nhiều hàm callback bên trong nhau, dẫn đến mã khó đọc, khó bảo trì. Đây là vấn đề phổ biến khi xử lý bất đồng bộ trước khi có Promiseasync/await.

getUser(id, (user) => { getPosts(user.id, (posts) => { getComments(posts[0].id, (comments) => { console.log(comments); }); }); });

Q: Promise là gì và giúp gì?
A: Promise là cách quản lý tác vụ bất đồng bộ. Nó đại diện cho một giá trị sẽ có trong tương lai và cho phép xử lý kết quả bằng .then().catch(), giúp tránh callback hell.

fetchData() .then(data => console.log(data)) .catch(error => console.error(error));

Q: Sự khác nhau giữa nullundefined trong thực tế là gì?
A: undefined thường xuất hiện khi biến chưa được gán, trong khi null là khi ta chủ động đặt giá trị là “rỗng”. Trong thực tế, bạn dùng null để reset giá trị, undefined là dấu hiệu thiếu sót.


Q: async/await hoạt động như thế nào?
A: async biến một hàm thành hàm bất đồng bộ và luôn trả về Promise. Từ khóa await tạm dừng hàm cho đến khi Promise hoàn thành, giúp code dễ đọc như code đồng bộ.

async function load() { const res = await fetch("/data"); const data = await res.json(); console.log(data); }

Q: Closure là gì?
A: Closure là khi một hàm “ghi nhớ” biến trong scope cha của nó, ngay cả khi scope đó đã kết thúc. Closure cho phép bạn tạo private variable hoặc lưu state trong hàm.

function counter() { let count = 0; return () => ++count; } const next = counter(); next(); // 1 next(); // 2

Q: Event loop trong JavaScript là gì?
A: Event loop là cơ chế giúp JavaScript xử lý tác vụ bất đồng bộ bằng cách quản lý call stack và task queue. Nó đảm bảo code đồng bộ chạy trước, rồi mới xử lý các callback bất đồng bộ.


Q: this trong JavaScript là gì?
A: this là từ khóa đại diện cho ngữ cảnh gọi hàm. Trong object method, this là object đó. Trong function thông thường, thisundefined (strict mode) hoặc window (non-strict). Arrow function không có this riêng.


Q: Debounce và Throttle khác nhau như thế nào?
A: Debounce chỉ gọi hàm sau khi người dùng ngưng thao tác một khoảng thời gian. Throttle giới hạn gọi hàm mỗi khoảng thời gian cố định. Cả hai đều dùng để tối ưu hiệu năng khi xử lý sự kiện như scroll hoặc input.


Q: DOM là gì?
A: DOM (Document Object Model) là mô hình cấu trúc tài liệu HTML dưới dạng cây. JavaScript dùng DOM để truy cập, thay đổi nội dung, thuộc tính và style của trang web.


Q: map() khác gì forEach()?
A: map() trả về mảng mới chứa kết quả sau xử lý từng phần tử, còn forEach() chỉ duyệt qua mảng mà không trả về gì. Dùng map() khi cần chuyển đổi dữ liệu.

const nums = [1, 2, 3]; const doubled = nums.map(n => n * 2); // [2, 4, 6]

Q: Toán tử spread và rest khác nhau như thế nào?
A: Cả hai dùng ..., nhưng spread dùng để tách phần tử từ mảng/object, còn rest dùng để gom phần tử vào một mảng.

// spread const arr = [1, 2, 3]; const copy = [...arr]; // rest function sum(...args) { return args.reduce((a, b) => a + b); }

Q: Tại sao nên tránh == khi so sánh?
A:== có thể gây ra những so sánh bất ngờ do ép kiểu ngầm. Ví dụ: '' == 0true. Dùng === giúp đảm bảo kiểm tra chặt chẽ hơn và ít lỗi hơn.


Q: Arrow function có được làm constructor không?
A: Không. Arrow function không có this, arguments, và cũng không có prototype, nên không dùng để tạo instance như constructor function bình thường.


Q: Optional chaining (?.) dùng để làm gì?
A: Giúp truy cập thuộc tính lồng nhau mà không bị lỗi nếu một trong các phần tử trung gian là null hoặc undefined.

const user = {}; console.log(user.profile?.email); // undefined, không lỗi

Q: JSON.stringify()JSON.parse() để làm gì?
A: stringify() biến object thành chuỗi JSON để lưu trữ/ gửi đi. parse() biến chuỗi JSON thành object. Dùng khi làm việc với API hoặc localStorage.


Q: Tại sao typeof NaN lại là "number"?
A: Đây là một “quirk” của JavaScript. NaN vẫn thuộc loại number, chỉ là nó không đại diện cho một giá trị hợp lệ.


Q: Sự khác nhau giữa == undefined=== undefined là gì?
A: == undefined trả về true cho cả nullundefined vì ép kiểu. === undefined thì chỉ true nếu thực sự là undefined.


Q: DOMContentLoaded khác gì window.onload?
A: DOMContentLoaded được gọi khi DOM sẵn sàng (trước khi ảnh tải xong), còn window.onload đợi mọi tài nguyên (ảnh, script) tải xong mới gọi. Dùng DOMContentLoaded để init sớm.


Q: Hàm nào trong JS giúp clone sâu object?
A: Dùng structuredClone(obj) hoặc JSON.parse(JSON.stringify(obj)) (có giới hạn). Thư viện như lodash.cloneDeep cũng hỗ trợ tốt clone sâu.


Q: == giữa []false trả về gì? Vì sao?
A: Trả về true vì JavaScript thực hiện ép kiểu phức tạp: [] được ép sang chuỗi "", rồi sang số 0, và false cũng thành 0. Vì vậy [] == falsetrue. Tránh dùng == vì dễ gây lỗi logic.


Q: Khi nào nên dùng try...catch?
A: Dùng khi có khả năng lỗi xảy ra, ví dụ: gọi API, parse JSON, đọc dữ liệu chưa chắc chắn. try...catch giúp không làm sập chương trình và xử lý lỗi một cách an toàn.

try { const data = JSON.parse('{"key": 123}'); console.log(data.key); } catch (err) { console.error("JSON lỗi:", err); }

Q: IIFE (Immediately Invoked Function Expression) là gì?
A: Là hàm được định nghĩa và chạy ngay lập tức. Dùng để tạo scope riêng, tránh làm bẩn global scope.

(function () { const msg = "Hello!"; console.log(msg); })();

Q: Sự khác biệt giữa synchronous và asynchronous là gì?
A: Synchronous: tác vụ chạy theo thứ tự, tác vụ sau phải đợi cái trước. Asynchronous: có thể tạm dừng và tiếp tục khi hoàn thành, không chặn dòng xử lý chính (non-blocking). JS dùng async để giữ UI mượt.


Q: localStorage, sessionStorage, cookie khác nhau gì?
A:

  • localStorage: lưu dữ liệu lâu dài, kể cả khi tắt trình duyệt.
  • sessionStorage: mất khi tab/trình duyệt đóng.
  • cookie: gửi theo mỗi request HTTP, nhỏ gọn, có thể cấu hình thời gian sống, bảo mật hơn.

Q: Làm sao để kiểm tra một biến là array?
A: Dùng Array.isArray(value) là cách đúng nhất. Tránh dùng typeoftypeof [] cũng trả về "object".


Q: Làm sao để tránh mutate object trong JS?
A: Clone object trước khi sửa. Dùng spread operator, Object.assign(), hoặc thư viện như lodash.

const newUser = { ...user, name: "Vu Nguyen" };

Q: setTimeout trong vòng lặp for thường sai vì sao?
A: Do closure giữ lại giá trị cuối của biến lặp. Cách giải quyết là dùng let, hoặc tạo closure riêng cho mỗi vòng.

for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // In ra: 0 1 2

Q: Làm sao để biết code có đang chạy async không?
A: Xem có dùng Promise, async/await, setTimeout, hoặc API bất đồng bộ như fetch. Các hàm async thường không trả kết quả ngay mà cần .then() hoặc await.


Q: Object.freeze() dùng để làm gì?
A: Làm cho object không thể thay đổi: không thêm, xoá, hay sửa property. Rất hữu ích khi muốn bảo vệ dữ liệu không bị thay đổi ngoài ý muốn.

const config = Object.freeze({ mode: "prod" }); config.mode = "dev"; // Không thay đổi được

JavaScript Interview Questions for Junior

A collection of basic JavaScript interview questions for Junior, with clear explanations and illustrative examples.


Q: What is callback hell?
A: Callback hell happens when you nest many callbacks inside each other, making the code hard to read and maintain. It was a common issue when handling async tasks before Promise and async/await existed.

getUser(id, (user) => { getPosts(user.id, (posts) => { getComments(posts[0].id, (comments) => { console.log(comments); }); }); });

Q: What is a Promise and how does it help?
A: A Promise is a way to manage asynchronous tasks. It represents a future value and allows handling results using .then() and .catch(), helping avoid callback hell.

fetchData() .then(data => console.log(data)) .catch(error => console.error(error));

Q: What’s the difference between null and undefined in practice?
A: undefined usually means a variable hasn't been assigned a value, while null is intentionally set to indicate "no value." Use null when you want to reset or clear a value, undefined signals missing data.


Q: How does async/await work?
A: async turns a function into one that always returns a Promise. await pauses the function until the Promise resolves. It makes async code look more like synchronous code.

async function load() { const res = await fetch("/data"); const data = await res.json(); console.log(data); }

Q: What is a closure?
A: A closure is when a function "remembers" variables from its outer scope, even after the outer function has finished. Closures are useful for creating private variables or preserving state.

function counter() { let count = 0; return () => ++count; } const next = counter(); next(); // 1 next(); // 2

Q: What is the event loop in JavaScript?
A: The event loop is a mechanism that handles asynchronous tasks in JavaScript by managing the call stack and task queue. It ensures synchronous code runs first, then handles async callbacks.


Q: What is this in JavaScript?
A: this refers to the context of a function call. In object methods, this refers to the object. In regular functions, it’s undefined in strict mode or window in non-strict mode. Arrow functions do not have their own this.


Q: What’s the difference between debounce and throttle?
A: Debounce delays a function until after user stops triggering it for a set time. Throttle limits how often a function runs in a given period. Both are useful for optimizing performance during events like scroll or input.


Q: What is the DOM?
A: The DOM (Document Object Model) represents HTML as a tree structure. JavaScript uses the DOM to access and change page content, attributes, and styles.


Q: How is map() different from forEach()?
A: map() returns a new array with transformed values, while forEach() simply iterates through the array without returning anything. Use map() when you need to transform data.

const nums = [1, 2, 3]; const doubled = nums.map(n => n * 2); // [2, 4, 6]

Q: What's the difference between spread and rest operators?
A: Both use ..., but spread is for unpacking elements, and rest is for gathering elements into an array.

// spread const arr = [1, 2, 3]; const copy = [...arr]; // rest function sum(...args) { return args.reduce((a, b) => a + b); }

Q: Why avoid using == for comparison?
A: Because == does type coercion and may produce unexpected results. For example: '' == 0 is true. Use === for safer and more predictable comparisons.


Q: Can arrow functions be used as constructors?
A: No. Arrow functions do not have their own this, arguments, or prototype, so they cannot be used to create instances like regular constructor functions.


Q: What is optional chaining (?.) used for?
A: It allows safely accessing deeply nested properties without throwing an error if an intermediate value is null or undefined.

const user = {}; console.log(user.profile?.email); // undefined, no error

Q: What are JSON.stringify() and JSON.parse() used for?
A: stringify() converts an object into a JSON string, useful for storing or sending data. parse() converts a JSON string back to an object. They're often used with APIs and localStorage.


Q: Why is typeof NaN equal to "number"?
A: It's a known quirk in JavaScript. NaN is still considered a number type, even though it’s not a valid number.


Q: What’s the difference between == undefined and === undefined?
A: == undefined returns true for both null and undefined due to type coercion. === undefined is strict and only returns true for actual undefined.


Q: What’s the difference between DOMContentLoaded and window.onload?
A: DOMContentLoaded fires when the DOM is ready, before images and other resources are loaded. window.onload waits for everything (images, scripts) to load. Use DOMContentLoaded for faster initialization.


Q: How do you deep clone an object in JS?
A: Use structuredClone(obj) or JSON.parse(JSON.stringify(obj)) (with some limitations). Libraries like lodash.cloneDeep are also helpful.


Q: What does [] == false return, and why?
A: It returns true due to JavaScript's coercion rules: [] becomes "", then 0, and false is also 0, so [] == falsetrue. Avoid == to prevent such logic errors.


Q: When should you use try...catch?
A: Use it when something might fail, like API calls, JSON parsing, or reading uncertain data. try...catch prevents your app from crashing and lets you handle errors safely.

try { const data = JSON.parse('{"key": 123}'); console.log(data.key); } catch (err) { console.error("JSON error:", err); }

Q: What is an IIFE (Immediately Invoked Function Expression)?
A: It’s a function that runs immediately after it's defined. It's useful for creating private scope and avoiding global pollution.

(function () { const msg = "Hello!"; console.log(msg); })();

Q: What's the difference between synchronous and asynchronous?
A: Synchronous code runs step by step, blocking the next task. Asynchronous code can pause and resume without blocking the main thread, which helps keep the UI responsive.


Q: What’s the difference between localStorage, sessionStorage, and cookie?
A:

  • localStorage: persists data even after browser is closed.
  • sessionStorage: cleared when tab/browser is closed.
  • cookie: sent with every HTTP request, smaller size, more suitable for auth/data with expiration and security needs.

Q: How to check if a variable is an array?
A: Use Array.isArray(value) — it's the most reliable. Avoid typeof since typeof [] is "object".


Q: How to avoid mutating objects in JavaScript?
A: Clone objects before modifying. Use the spread operator, Object.assign(), or libraries like lodash.

const newUser = { ...user, name: "Vu Nguyen" };

Q: Why does setTimeout in a for loop often behave unexpectedly?
A: It’s due to closures keeping the last loop value. Use let or create a closure for each iteration to fix it.

for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // Logs: 0 1 2

Q: How to know if code is running asynchronously?
A: Check if it uses Promise, async/await, setTimeout, or async APIs like fetch. Async functions don’t return immediate results — they need .then() or await.


Q: What does Object.freeze() do?
A: It makes an object immutable — you can’t add, delete, or change its properties. It's useful for protecting data from accidental modification.

const config = Object.freeze({ mode: "prod" }); config.mode = "dev"; // Won’t change

Tags

Buy Me A Coffee
    JavaScriptInterview