Closure là một tính năng trong JavaScript cho phép một hàm truy cập và sử dụng các biến từ phạm vi bên ngoài của nó, bao gồm cả các biến đã thoát khỏi phạm vi của hàm. Điều này có nghĩa là các biến vẫn có thể được truy cập ngay cả sau khi hàm đã hoàn thành việc thực thi của nó.
Hãy xem một ví dụ đơn giản về Closure trong JavaScript:
function outerFunction() {
var message = 'Hello';
function innerFunction() {
console.log(message);
}
return innerFunction;
}
var myFunction = outerFunction();
myFunction(); // In ra: Hello
Trong ví dụ trên, chúng ta có một hàm outerFunction
chứa một biến message
và một hàm innerFunction
được khai báo trong outerFunction
. Hàm outerFunction
trả về hàm innerFunction
.
Khi chúng ta gọi outerFunction
và gán kết quả trả về cho biến myFunction
, biến message
vẫn được giữ lại trong bộ nhớ, mặc dù hàm outerFunction
đã hoàn thành việc thực thi của nó. Sau đó, khi chúng ta gọi hàm myFunction
, nó vẫn có thể truy cập và in ra giá trị của biến message
.
Đây chính là ví dụ về Closure, khi một hàm innerFunction
có thể truy cập biến message
từ phạm vi bên ngoài của nó.
Closure cho phép chúng ta tạo ra các biến riêng tư bằng cách sử dụng hàm. Điều này có nghĩa là các biến chỉ có thể được truy cập và sử dụng trong phạm vi của hàm đó, không thể truy cập từ bên ngoài. Đây là một cách tuyệt vời để ẩn thông tin và bảo vệ dữ liệu.
function createCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter = createCounter();
counter(); // In ra: 1
counter(); // In ra: 2
Trong ví dụ trên, chúng ta có một hàm createCounter
tạo ra một biến count
và trả về một hàm khác. Hàm được trả về có thể truy cập và tăng giá trị của count
mỗi khi nó được gọi. Biến count
không thể truy cập trực tiếp từ bên ngoài createCounter
, nhưng chỉ có thể được sử dụng thông qua hàm được trả về.
Closure cũng cho phép chúng ta tạo ra các hàm gọi lại (callback) để xử lý các sự kiện hoặc tác vụ bất đồng bộ. Chúng ta có thể truyền các biến và tham số vào hàm gọi lại và sử dụng chúng trong quá trình xử lý.
function fetchData(url, callback) {
// Khi dữ liệu đã được tải về
const data = 'Dữ liệu từ API';
// Gọi hàm gọi lại và truyền dữ liệu vào
callback(data);
}
function processResponse(response) {
console.log('Xử lý dữ liệu:', response);
}
fetchData('https://api.example.com', processResponse);
Trong ví dụ trên, chúng ta có một hàm fetchData
để tải dữ liệu từ một URL. Chúng ta cũng có một hàm processResponse
để xử lý dữ liệu đã tải về. Bằng cách sử dụng Closure, chúng ta có thể truyền hàm processResponse
làm hàm gọi lại và sử dụng dữ liệu đã tải về trong hàm này.
Closure cung cấp cho chúng ta khả năng tạo ra các biến duy trì trạng thái (stateful variables). Điều này có nghĩa là các biến vẫn giữ lại giá trị của chúng sau khi hàm đã hoàn thành việc thực thi của nó. Điều này rất hữu ích trong việc lưu trạng thái hoặc thông tin quan trọng giữa các lần gọi hàm.
function createLogger() {
let logs = [];
return {
addLog: function(message) {
logs.push(message);
console.log('Log:', message);
},
getLogs: function() {
return logs;
}
};
}
const logger = createLogger();
logger.addLog('Bắt đầu quá trình xử lý');
logger.addLog('Hoàn thành quá trình xử lý');
console.log(logger.getLogs()); // In ra: ['Bắt đầu quá trình xử lý', 'Hoàn thành quá trình xử lý']
Trong ví dụ trên, chúng ta có một hàm createLogger
tạo ra một mảng logs
và trả về một đối tượng với hai phương thức. Phương thức addLog
được sử dụng để thêm log vào mảng logs
, trong khi phương thức getLogs
trả về mảng logs
. Bằng cách sử dụng Closure, mỗi lần gọi hàm addLog
, mảng logs
vẫn duy trì và lưu trạng thái giữa các lần gọi.