Closure (Đóng gói) là một khái niệm cốt lõi trong JavaScript: một hàm nội bộ (inner function) vẫn có quyền truy cập vào biến của hàm ngoại bộ (outer function) sau khi hàm ngoại bộ đã thực thi xong và trả về.
Nói đơn giản: Hàm nhớ được môi trường nơi nó được tạo ra.
Ví dụ minh họa
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript Closure</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
.result { font-size: 20px; font-weight: 500; margin: 10px 0; }
button { padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>JavaScript Closure - Ví dụ cộng hai số</h1>
<div style="color: green;" class="result" id="result"></div>
<button class="Btn" id="btn">NHẤN VÀO ĐÂY</button>
<h3> Nhấn nút để cộng hai số sử dụng closure </h3>
<script>
const resEle = document.querySelector("#result");
// Hàm ngoại bộ trả về hàm nội bộ
function add(num) {
// Hàm nội bộ "nhớ" biến num từ phạm vi bên ngoài
return function addInner(num1) {
resEle.innerHTML += `${num} + ${num1} = ${num + num1}
`;
};
}
document.querySelector("#btn").addEventListener("click", () => {
// Tạo closure: storeadd "nhớ" num = 99
const storeAdd = add(99);
// Gọi hàm nội bộ với num1 = 44
storeAdd(44); // Hiển thị: 99 + 44 = 143
// Có thể gọi lại nhiều lần, vẫn nhớ num = 99
storeAdd(10); // Hiển thị thêm: 99 + 10 = 109
});
</script>
</body>
</html>
Kết quả
Mỗi lần nhấn nút, hiển thị:
99 + 44 = 143 99 + 10 = 109
Ứng dụng thực tế của Closure:
- Data encapsulation (Đóng gói dữ liệu): Tạo biến private
- Function factories: Tạo hàm với cấu hình khác nhau
- Callback & Event handlers: Giữ trạng thái
- Module pattern: Tổ chức code
Ví dụ: Counter với biến private
function createCounter() {
let count = 0; // Biến private, không truy cập trực tiếp từ ngoài
return {
increment: () => ++count,
decrement: () => --count,
getValue: () => count
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getValue()); // 2
// count không thể truy cập: counter.count // undefined
Lưu ý: Closure có thể gây rò rỉ bộ nhớ (memory leak) nếu không cẩn thận với các tham chiếu lớn.