JavaScript là một trong những ngôn ngữ lập trình phổ biến nhất hiện nay và thường xuyên xuất hiện trong các cuộc phỏng vấn lập trình. Dưới đây là 5 câu hỏi phổ biến về JavaScript cùng câu trả lời và giải thích chi tiết.

1. Hoisting trong JavaScript là gì?

Trả lời:

Hoisting là một cơ chế trong JavaScript, trong đó các khai báo biến và hàm được "đưa lên" (hoisted) đầu phạm vi của chúng trước khi thực thi mã.

Giải thích:

  • Khi một biến hoặc một hàm được khai báo, JavaScript sẽ đưa phần khai báo lên đầu phạm vi của nó trước khi thực thi mã.
  • Điều này có nghĩa là bạn có thể sử dụng biến hoặc hàm trước khi chúng được khai báo trong mã.

Ví dụ:

js
console.log(a); // undefined
var a = 5;
console.log(a); // 5

Trong trường hợp trên, JavaScript "hoisted" khai báo var a lên đầu phạm vi nhưng không hoisted giá trị gán (5). Do đó, khi truy xuất a trước khi gán, nó trả về undefined.

Tuy nhiên, với letconst, hoisting vẫn xảy ra nhưng biến không được khởi tạo trước khi sử dụng:

js
console.log(b); // ReferenceError
let b = 10;

2. Sự khác biệt giữa toán tử "==" và "===" trong JavaScript?

Trả lời:

  • == (so sánh lỏng lẻo) chỉ so sánh giá trị, không quan tâm đến kiểu dữ liệu.
  • === (so sánh chặt chẽ) so sánh cả giá trị lẫn kiểu dữ liệu.

Ví dụ:

js
console.log(5 == "5");  // true (chuyển đổi kiểu dữ liệu tự động)
console.log(5 === "5"); // false (khác kiểu dữ liệu)

Lời khuyên: Luôn sử dụng === để tránh lỗi không mong muốn do chuyển đổi kiểu dữ liệu tự động.

3. Sự khác biệt giữa var, let và const trong JavaScript?

Trả lời:

  • var: Có phạm vi function scope, bị hoisting, có thể khai báo lại và cập nhật giá trị.
  • let: Có phạm vi block scope, bị hoisting nhưng không được sử dụng trước khi khai báo.
  • const: Có phạm vi block scope, không thể gán lại giá trị sau khi đã khởi tạo.

Ví dụ:

js
var x = 10;
let y = 20;
const z = 30;

x = 15; // Hợp lệ
y = 25; // Hợp lệ
z = 35; // Lỗi: Assignment to constant variable.

4. Sự khác biệt giữa Promise và async/await trong Node.js?

Trả lời:

  • Promise là một đối tượng đại diện cho một giá trị có thể có ngay bây giờ, hoặc trong tương lai (thành công hoặc thất bại).
  • async/await là cú pháp giúp xử lý bất đồng bộ dễ dàng hơn, giúp mã trông giống như mã đồng bộ.

Ví dụ:

Promise:

js
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve("Dữ liệu tải thành công"), 2000);
  });
}

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

Async/Await:

js
async function fetchDataAsync() {
  try {
    let data = await fetchData();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

fetchDataAsync();

Lời khuyên: Sử dụng async/await khi có thể, vì nó giúp mã dễ đọc hơn so với Promise chaining.

5. Sự khác biệt giữa Microtask Queue và Callback Queue?

Trả lời:

  • Microtask Queue chứa các công việc có mức độ ưu tiên cao như Promises, process.nextTick() (Node.js).
  • Callback Queue (Task Queue) chứa các công việc như setTimeout, setInterval, setImmediate (Node.js).

Ví dụ:

js
console.log("Start");

setTimeout(() => console.log("Timeout Callback"), 0);

Promise.resolve().then(() => console.log("Promise Callback"));

console.log("End");

Kết quả thực thi:

shell
Start
End
Promise Callback
Timeout Callback

Giải thích:

  • console.log("Start")console.log("End") chạy trước vì thuộc main thread.
  • Promise callback được ưu tiên xử lý trước trong Microtask Queue.
  • Callback từ setTimeout chỉ chạy sau khi Microtask Queue đã hoàn tất.

Kết luận

Các câu hỏi trên không chỉ giúp bạn chuẩn bị tốt hơn cho các buổi phỏng vấn JavaScript mà còn giúp hiểu rõ hơn về cơ chế hoạt động của ngôn ngữ này. Nếu bạn muốn luyện tập thêm, hãy truy cập CodeTutHub để tìm hiểu thêm nhiều câu hỏi phỏng vấn thú vị khác! 🚀