🔰 PHẦN 1: CƠ BẢN
1. Câu hỏi: JavaScript là gì?
-
Lời giải:
JavaScript là một ngôn ngữ lập trình phổ biến dùng để xây dựng các chức năng tương tác trên website. Ban đầu, JavaScript chỉ chạy trên trình duyệt (frontend), nhưng hiện nay có thể chạy trên server (backend) thông qua Node.js. Nó giúp xử lý sự kiện, thao tác DOM và gọi API. - Code demo:
document.querySelector("button").onclick = () => {
alert("Hello JS");
};
2. Câu hỏi: var, let, const khác nhau như thế nào?
-
Lời giải:
Ba cách khai báo biến này khác nhau ở phạm vi hoạt động (scope) và khả năng thay đổi giá trị: -
var: có phạm vi trong function, có thể bị truy cập ngoài block{}và dễ gây lỗi -
let: có phạm vi trong block{}, an toàn hơn -
const: giốngletnhưng không thể gán lại giá trị sau khi đã khai báo
👉 Nên dùngconstmặc định, chỉ dùngletkhi cần thay đổi giá trị - Code demo:
if (true) {
var a = 1;
let b = 2;
}
console.log(a); // 1
console.log(b); // lỗi
3. Câu hỏi: Hoisting là gì?
-
Lời giải:
Hoisting là cơ chế mà JavaScript tự động đưa phần khai báo biến và function lên đầu phạm vi (scope) trước khi thực thi code. Tuy nhiên, chỉ phần khai báo được đưa lên, còn giá trị thì không. - Code demo:
console.log(a); // undefined
var a = 5;
4. Câu hỏi: Scope là gì?
-
Lời giải:
Scope là phạm vi mà một biến có thể được truy cập. Có 3 loại chính: - Global scope: dùng được mọi nơi
- Function scope: chỉ dùng trong function
-
Block scope: chỉ dùng trong
{}(áp dụng cholet,const) - Code demo:
let a = 1;
function test() {
let b = 2;
}
5. Câu hỏi: Closure là gì?
-
Lời giải:
Closure là khi một function có thể truy cập và ghi nhớ các biến ở scope bên ngoài của nó, ngay cả khi function bên ngoài đã kết thúc. Đây là cơ chế giúp tạo biến “private” trong JavaScript. - Code demo:
function counter() {
let count = 0;
return function () {
count++;
return count;
};
}
const c = counter();
console.log(c()); // 1
console.log(c()); // 2
6. Câu hỏi: == và === khác nhau thế nào?
- Lời giải:
-
==: so sánh giá trị nhưng có ép kiểu dữ liệu (có thể gây lỗi logic) -
===: so sánh cả giá trị và kiểu dữ liệu (an toàn hơn)
👉 Trong thực tế nên luôn dùng=== - Code demo:
console.log(1 == "1"); // true
console.log(1 === "1"); // false
7. Câu hỏi: null và undefined khác nhau như thế nào?
- Lời giải:
-
undefined: biến đã khai báo nhưng chưa gán giá trị -
null: giá trị rỗng do lập trình viên chủ động gán
👉 Hiểu đơn giản:undefinedlà “chưa có”,nulllà “có nhưng rỗng” - Code demo:
let a;
let b = null;
8. Câu hỏi: Các kiểu dữ liệu trong JavaScript là gì?
-
Lời giải:
JavaScript có 2 nhóm kiểu dữ liệu: - Primitive: string, number, boolean, null, undefined, symbol, bigint
-
Reference: object, array, function
👉 Primitive lưu trực tiếp giá trị, object lưu theo tham chiếu - Code demo:
typeof "hello"; // string
typeof 123; // number
typeof {}; // object
9. Câu hỏi: Primitive và Reference khác nhau như thế nào?
- Lời giải:
- Primitive: khi gán sẽ copy giá trị
-
Reference: khi gán sẽ copy địa chỉ trong bộ nhớ
👉 Vì vậy thay đổi object sẽ ảnh hưởng biến gốc - Code demo:
let a = 1;
let b = a;
b = 2;
console.log(a); // 1
let obj1 = { x: 1 };
let obj2 = obj1;
obj2.x = 2;
console.log(obj1.x); // 2
10. Câu hỏi: Function declaration và function expression khác nhau thế nào?
- Lời giải:
- Function declaration: được hoisting (có thể gọi trước khi khai báo)
-
Function expression: không được hoisting
👉 Function expression thường dùng trong thực tế nhiều hơn - Code demo:
// declaration
function a() {}
// expression
const b = function () {};
11. Câu hỏi: Arrow function là gì?
-
Lời giải:
Arrow function là cách viết ngắn gọn của function trong ES6. Nó giúp code gọn hơn và không cóthisriêng, mà dùngthistừ bên ngoài. - Code demo:
const add = (a, b) => a + b;
12. Câu hỏi: this trong JavaScript là gì?
-
Lời giải:
thislà từ khóa đại diện cho đối tượng đang gọi function. Giá trị củathisphụ thuộc vào cách function được gọi, không phải nơi nó được khai báo. - Code demo:
const obj = {
name: "JS",
show() {
console.log(this.name);
}
};
obj.show(); // JS
13. Câu hỏi: Event là gì?
-
Lời giải:
Event là các hành động xảy ra trên trang web như click, scroll, nhập dữ liệu… JavaScript dùng event để xử lý tương tác của người dùng. - Code demo:
button.addEventListener("click", () => {
console.log("Clicked");
});
14. Câu hỏi: Callback function là gì?
-
Lời giải:
Callback là một function được truyền vào function khác như một tham số, và sẽ được gọi lại sau khi một công việc hoàn thành (thường dùng trong async). - Code demo:
function run(callback) {
callback();
}
run(() => console.log("Hello"));
15. Câu hỏi: NaN là gì?
-
Lời giải:
NaN (Not a Number) là giá trị đại diện cho kết quả không hợp lệ trong các phép toán số học. - Code demo:
console.log("abc" * 2); // NaN
⚙️ PHẦN 2: TRUNG CẤP
16. Câu hỏi: Promise là gì?
-
Lời giải:
Promise là một đối tượng dùng để xử lý các tác vụ bất đồng bộ (async) trong JavaScript. Nó giúp bạn xử lý kết quả của một công việc trong tương lai (ví dụ: gọi API).
Promise có 3 trạng thái: -
pending: đang chờ xử lý -
fulfilled: xử lý thành công -
rejected: xử lý thất bại
👉 Promise giúp code dễ đọc hơn so với callback (tránh callback hell)
- Code demo:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Success"), 1000);
});
promise.then(res => console.log(res));
17. Câu hỏi: Async/Await là gì?
-
Lời giải:
Async/Await là cú pháp giúp viết code bất đồng bộ theo kiểu đồng bộ, dễ đọc và dễ hiểu hơn Promise. -
async: khai báo function bất đồng bộ -
await: chờ Promise hoàn thành trước khi chạy tiếp
👉 Giúp code nhìn “thẳng” hơn, dễ debug hơn
- Code demo:
async function run() {
const result = await Promise.resolve(10);
console.log(result);
}
run();
18. Câu hỏi: Event Loop là gì?
-
Lời giải:
Event Loop là cơ chế giúp JavaScript xử lý các tác vụ bất đồng bộ dù chỉ chạy trên một luồng (single-thread).
Cách hoạt động:
- Code chạy trong Call Stack
- Task async (setTimeout, Promise...) được đưa ra ngoài
- Khi xong → đưa vào Queue
- Event Loop sẽ đưa task từ Queue vào lại Stack khi rảnh
👉 Giúp JS không bị block khi xử lý async
- Code demo:
console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// Kết quả: 1 4 3 2
19. Câu hỏi: Call Stack là gì?
-
Lời giải:
Call Stack là nơi JavaScript lưu trữ các function đang được thực thi. Nó hoạt động theo nguyên tắc LIFO (Last In First Out).
👉 Function nào gọi sau sẽ chạy trước - Code demo:
function a() {
b();
}
function b() {
console.log("Run");
}
a();
20. Câu hỏi: Microtask và Macrotask khác nhau thế nào?
-
Lời giải:
JavaScript có 2 loại hàng đợi: - Microtask: Promise, queueMicrotask → ưu tiên cao
- Macrotask: setTimeout, setInterval → ưu tiên thấp hơn
👉 Event Loop luôn chạy Microtask trước
- Code demo:
setTimeout(() => console.log("macro"), 0);
Promise.resolve().then(() => console.log("micro"));
// Output: micro → macro
21. Câu hỏi: setTimeout hoạt động như thế nào?
-
Lời giải:
setTimeout không chạy ngay lập tức sau thời gian delay, mà nó đưa callback vào hàng đợi. Callback chỉ được chạy khi Call Stack rảnh.
👉 Vì vậy delay = 0 không có nghĩa là chạy ngay - Code demo:
setTimeout(() => console.log("run"), 0);
console.log("end");
// Output: end → run
22. Câu hỏi: Deep copy và Shallow copy là gì?
- Lời giải:
- Shallow copy: chỉ copy cấp 1, object bên trong vẫn dùng chung reference
- Deep copy: copy toàn bộ, không bị ảnh hưởng lẫn nhau
👉 Dùng deep copy khi làm việc với object lồng nhau
- Code demo:
const obj = { a: { b: 1 } };
const shallow = { ...obj };
const deep = JSON.parse(JSON.stringify(obj));
23. Câu hỏi: Object.assign() và spread operator khác nhau thế nào?
-
Lời giải:
Cả hai đều dùng để copy hoặc merge object: -
Object.assign(): method truyền thống -
...spread: cú pháp mới, dễ đọc hơn
👉 Trong thực tế, nên dùng spread
- Code demo:
const a = { x: 1 };
const b = { y: 2 };
const c = Object.assign({}, a, b);
const d = { ...a, ...b };
24. Câu hỏi: map, filter, reduce khác nhau thế nào?
- Lời giải:
-
map(): biến đổi từng phần tử -
filter(): lọc phần tử theo điều kiện -
reduce(): gom dữ liệu thành 1 giá trị
👉 Đây là 3 method rất quan trọng trong xử lý mảng
- Code demo:
const arr = [1, 2, 3];
arr.map(x => x * 2); // [2,4,6]
arr.filter(x => x > 1); // [2,3]
arr.reduce((s, x) => s+x, 0); // 6
25. Câu hỏi: Prototype là gì?
-
Lời giải:
Prototype là cơ chế giúp các object trong JavaScript kế thừa thuộc tính và phương thức từ object khác.
👉 Đây là nền tảng của OOP trong JS - Code demo:
function Person(name) {
this.name = name;
}
Person.prototype.say = function() {
console.log(this.name);
};
26. Câu hỏi: Prototype chain là gì?
-
Lời giải:
Prototype chain là chuỗi liên kết các object với nhau thông qua prototype. Khi truy cập thuộc tính, JS sẽ tìm từ object hiện tại → lên prototype → cho đến Object gốc.
👉 Đây là cơ chế tìm kiếm thuộc tính trong JS - Code demo:
const obj = {};
console.log(obj.toString()); // từ Object.prototype
27. Câu hỏi: bind, call, apply khác nhau thế nào?
-
Lời giải:
Cả 3 đều dùng để thay đổithis: -
call: gọi function ngay, truyền tham số từng cái -
apply: giống call nhưng truyền mảng -
bind: trả về function mới, chưa gọi
👉 bind thường dùng trong React hoặc event
- Code demo:
function greet(name) {
console.log(this.title + name);
}
greet.call({ title: "Mr " }, "A");
greet.apply({ title: "Mr " }, ["B"]);
const fn = greet.bind({ title: "Mr " });
fn("C");
28. Câu hỏi: this trong arrow function khác gì function thường?
- Lời giải:
-
Function thường:
thisphụ thuộc cách gọi -
Arrow function: không có
thisriêng, nó dùngthistừ scope bên ngoài
👉 Đây là điểm dễ gây bug
- Code demo:
const obj = {
name: "JS",
show: () => console.log(this.name)
};
obj.show(); // undefined
29. Câu hỏi: Module trong JavaScript là gì?
-
Lời giải:
Module giúp chia code thành nhiều file nhỏ, dễ quản lý và tái sử dụng.
👉 Dùngexportvàimport - Code demo:
// a.js
export const a = 1;
// b.js
import { a } from "./a.js";
30. Câu hỏi: ES6 có những gì nổi bật?
-
Lời giải:
ES6 (ECMAScript 2015) mang lại nhiều cải tiến: - let, const
- arrow function
- destructuring
- spread operator
- class, module
👉 Giúp code hiện đại và dễ đọc hơn
- Code demo:
const { a } = { a: 1 };
const arr = [...[1,2,3]];
🚀 PHẦN 3
31. Câu hỏi: Debounce là gì?
-
Lời giải:
Debounce là kỹ thuật chỉ thực thi function sau khi người dùng ngừng thao tác trong một khoảng thời gian.
👉 Dùng cho search input, resize - Code demo:
function debounce(fn, delay) {
let timer;
return () => {
clearTimeout(timer);
timer = setTimeout(fn, delay);
};
}
32. Câu hỏi: Currying là gì?
-
Lời giải:
Currying là kỹ thuật biến một function nhiều tham số thành chuỗi function mỗi function nhận một tham số. - Code demo:
const add = a => b => a + b;
add(2)(3);
33. Câu hỏi: Memoization là gì?
-
Lời giải:
Memoization là kỹ thuật lưu cache kết quả của function để tránh tính toán lại. - Code demo:
const cache = {};
function memo(n) {
if (cache[n]) return cache[n];
return cache[n] = n * 2;
}
34. Câu hỏi: Generator là gì?
-
Lời giải:
Generator là function có thể tạm dừng và tiếp tục thực thi bằng từ khóayield. - Code demo:
function* gen() {
yield 1;
yield 2;
}
36. Câu hỏi: Map và WeakMap khác nhau thế nào?
- Lời giải:
-
Map: key có thể là bất kỳ kiểu dữ liệu nào -
WeakMap: key phải là object và sẽ tự động bị xóa khi object không còn tham chiếu
👉 WeakMap giúp tránh memory leak
- Code demo:
let wm = new WeakMap();
let obj = {};
wm.set(obj, "data");
obj = null; // GC có thể dọn
37. Câu hỏi: Set và WeakSet khác nhau thế nào?
- Lời giải:
-
Set: lưu các giá trị duy nhất -
WeakSet: chỉ lưu object và không ngăn GC
👉 WeakSet thường dùng để tracking object
- Code demo:
let set = new Set([1, 2, 2]);
console.log(set); // {1,2}
38. Câu hỏi: Symbol là gì?
-
Lời giải:
Symbol là kiểu dữ liệu dùng để tạo ra các giá trị duy nhất, thường dùng làm key trong object để tránh trùng lặp. - Code demo:
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false
39. Câu hỏi: Proxy là gì?
-
Lời giải:
Proxy cho phép bạn “chặn” và kiểm soát các thao tác trên object như get, set, delete...
👉 Dùng để validate, log hoặc bảo mật
- Code demo:
const obj = new Proxy({}, {
get(target, prop) {
return prop in target ? target[prop] : 0;
}
});
console.log(obj.a); // 0
40. Câu hỏi: Reflect là gì?
-
Lời giải:
Reflect là một API cung cấp các phương thức để thao tác với object một cách rõ ràng và chuẩn hơn so với cách truyền thống.
👉 Thường dùng cùng Proxy
- Code demo:
const obj = { a: 1 };
console.log(Reflect.get(obj, "a")); // 1
41. Câu hỏi: Tree shaking là gì?
-
Lời giải:
Tree shaking là kỹ thuật loại bỏ những đoạn code không được sử dụng khi build project, giúp giảm dung lượng file và tăng hiệu năng.
👉 Thường dùng trong Webpack, Vite
- Code demo:
// import nhưng không dùng → sẽ bị loại bỏ khi build
import { unused } from "./lib";
42. Câu hỏi: Lazy loading là gì?
-
Lời giải:
Lazy loading là kỹ thuật chỉ tải tài nguyên khi cần thiết, thay vì tải toàn bộ ngay từ đầu.
👉 Giúp giảm thời gian load ban đầu
- Code demo:
import("./module.js").then(module => {
module.run();
});
43. Câu hỏi: Garbage Collection trong JS hoạt động thế nào?
-
Lời giải:
Garbage Collection là cơ chế tự động dọn dẹp bộ nhớ của JavaScript. Nó sẽ giải phóng những object không còn được tham chiếu đến.
👉 Tránh memory leak
- Code demo:
let obj = { a: 1 };
obj = null; // GC sẽ dọn
44. Câu hỏi: JavaScript là single-thread nghĩa là gì?
-
Lời giải:
JavaScript chỉ có một luồng thực thi, nghĩa là tại một thời điểm chỉ xử lý một tác vụ.
👉 Async (Event Loop) giúp JS không bị block
- Code demo:
while (true) {
// block toàn bộ chương trình
}
45. Câu hỏi: Web Worker là gì?
-
Lời giải:
Web Worker cho phép chạy JavaScript trên một luồng riêng biệt, không ảnh hưởng đến UI chính.
👉 Dùng cho task nặng (xử lý dữ liệu lớn)
- Code demo:
const worker = new Worker("worker.js");
worker.postMessage("start");
💼 PHẦN 4: THỰC CHIẾN
46. Câu hỏi: Làm sao tối ưu hiệu năng JavaScript?
-
Lời giải:
Một số cách phổ biến: - Sử dụng debounce/throttle
- Lazy loading
- Giảm thao tác DOM
- Sử dụng caching
👉 Tùy bài toán để chọn cách phù hợp
- Code demo:
window.addEventListener("scroll", debounce(() => {
console.log("scroll");
}, 200));
47. Câu hỏi: Làm sao debug JavaScript hiệu quả?
- Lời giải:
-
Sử dụng
console.log -
Dùng
debugger - Dùng Chrome DevTools để đặt breakpoint
👉 Debug là kỹ năng quan trọng khi đi làm
- Code demo:
function test() {
debugger;
let a = 1;
}
48. Câu hỏi: Memory leak là gì và xử lý thế nào?
-
Lời giải:
Memory leak xảy ra khi bộ nhớ không được giải phóng dù không còn sử dụng.
👉 Nguyên nhân:
- Không clear event listener
- Không clear timer
👉 Cách xử lý:
- cleanup khi component unmount
- Code demo:
const id = setInterval(() => {}, 1000);
clearInterval(id);
49. Câu hỏi: Tổ chức code JS trong project lớn?
- Lời giải:
- Chia module (MVC hoặc Clean Architecture)
- Tách logic và UI
- Dùng folder rõ ràng
👉 Giúp maintain dễ hơn
- Code demo:
// service.js
export const getUser = () => {};
// controller.js
import { getUser } from "./service";
50. Câu hỏi: Race condition là gì và xử lý thế nào?
-
Lời giải:
Race condition xảy ra khi nhiều tác vụ async chạy cùng lúc và kết quả trả về không đúng thứ tự.
👉 Cách xử lý:
- Hủy request cũ
- Dùng flag hoặc AbortController
- Code demo:
let current = 0;
async function fetchData() {
const id = ++current;
const res = await fetch("api");
if (id !== current) return; // bỏ kết quả cũ
}