Họ đang đo gì
Bạn hiểu closure như một cơ chế bạn dùng có chủ đích, hay chỉ như một thuật ngữ trong sách.
Trả lời ngắn~30 giây
Closure là hàm cộng với môi trường từ vựng nơi nó được ĐỊNH NGHĨA — nên nó vẫn đọc được biến của hàm bao ngoài kể cả sau khi hàm đó đã return. Mình dùng nhiều nhất cho ba việc: giữ trạng thái riêng tư mà không cần class, tạo hàm cấu hình sẵn như debounce/throttle, và giữ ngữ cảnh trong callback.
Giải thích sâu
Điểm hay bị hiểu sai: closure giữ THAM CHIẾU tới binding, không phải bản sao giá trị. Đó là lý do vòng lặp var in ra toàn giá trị cuối — ba closure chia nhau đúng một binding. Và cũng vì thế mà closure sửa được biến bên ngoài, thứ khiến nó dùng làm bộ đếm hay bộ nhớ đệm được.
Mặt sau ít được nói tới là bộ nhớ. Chừng nào closure còn sống thì toàn bộ môi trường nó tham chiếu còn sống theo — kể cả biến nó không dùng, tuỳ engine. Một listener DOM giữ closure trỏ tới một mảng lớn sẽ giữ mảng đó lại sau khi component đã bị gỡ, và đây là dạng rò rỉ bộ nhớ phổ biến nhất của SPA. Việc gỡ listener khi dọn dẹp không phải hình thức.
Ba cách dùng thật
// 1. Trạng thái riêng tư — không ai chạm được vào `count` từ bên ngoài
function makeCounter() {
let count = 0;
return { inc: () => ++count, get: () => count };
}
// 2. Hàm cấu hình sẵn
const debounce = (fn, ms) => {
let timer; // <- sống giữa các lần gọi
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), ms);
};
};
// 3. Rò rỉ: closure giữ `rows` sống mãi cùng listener
const rows = await fetchHugeTable();
window.addEventListener('resize', () => layout(rows));
// -> phải removeEventListener, nếu không `rows` không bao giờ được thu hồiCâu hỏi tiếp theo họ sẽ hỏi
?Closure và scope khác nhau chỗ nào?
Scope là quy tắc tra cứu biến lúc biên dịch; closure là hệ quả lúc chạy — hàm mang theo scope của nơi nó sinh ra. Nói cách khác, scope là luật, closure là thứ còn lại sau khi hàm bao ngoài đã kết thúc.
?Trong React, closure gây bug gì?
Stale closure: một callback trong useEffect bắt lấy state của lần render nó được tạo, nên nếu mảng phụ thuộc thiếu, nó vẫn đọc giá trị cũ mãi. Cách xử lý là khai báo đủ phụ thuộc, hoặc dùng dạng hàm cập nhật setX(prev => …) để không cần đọc giá trị hiện tại.
Trả lời thế này là mất điểm
- Đọc định nghĩa sách giáo khoa rồi im. Người phỏng vấn hỏi “dùng vào việc gì” là có lý do.
- Không biết closure có thể giữ bộ nhớ. Đây là câu hỏi tiếp theo gần như chắc chắn ở vòng mid.