JavaScript Closures
Các biến JavaScript có thể thuộc phạm vi cục bộ hoặc toàn cầu .
Các biến toàn cục có thể được tạo cục bộ (riêng tư) với các bao đóng .
Biến toàn cục
A function
có thể truy cập tất cả các biến được xác định bên trong hàm, như sau:
Thí dụ
function myFunction() {
let a = 4;
return a * a;
}
Nhưng a function
cũng có thể truy cập các biến được định nghĩa bên ngoài hàm, như sau:
Thí dụ
let a = 4;
function myFunction() {
return a * a;
}
Trong ví dụ cuối cùng, a là một biến toàn cục.
Trong một trang web, các biến toàn cục thuộc về đối tượng window.
Các biến toàn cục có thể được sử dụng (và thay đổi) bởi tất cả các tập lệnh trong trang (và trong cửa sổ).
Trong ví dụ đầu tiên, a là một biến cục bộ.
Một biến cục bộ chỉ có thể được sử dụng bên trong hàm nơi nó được định nghĩa. Nó bị ẩn khỏi các chức năng khác và mã script khác.
Các biến cục bộ và toàn cục có cùng tên là các biến khác nhau. Sửa đổi một, không sửa đổi khác.
Các biến được tạo mà không có từ khóa khai báo ( var
,
let
hoặc const
) luôn là toàn cục, ngay cả khi chúng được tạo bên trong một hàm.
Thí dụ
function myFunction() {
a = 4;
}
Thời gian tồn tại có thể thay đổi
Các biến toàn cục tồn tại cho đến khi trang bị hủy, như khi bạn điều hướng đến một trang khác hoặc đóng cửa sổ.
Các biến cục bộ có tuổi thọ ngắn. Chúng được tạo khi hàm được gọi và bị xóa khi hàm kết thúc.
Một tình thế tiến thoái lưỡng nan
Giả sử bạn muốn sử dụng một biến để đếm thứ gì đó và bạn muốn bộ đếm này có sẵn cho tất cả các hàm.
Bạn có thể sử dụng một biến toàn cục và một function
để tăng bộ đếm:
Thí dụ
// Initiate counter
let counter = 0;
// Function to increment
counter
function add() {
counter += 1;
}
// Call add() 3 times
add();
add();
add();
// The counter should now be 3
Có một vấn đề với giải pháp ở trên: Bất kỳ mã nào trên trang đều có thể thay đổi bộ đếm, mà không cần gọi add ().
Bộ đếm phải là cục bộ đối với add()
hàm, để ngăn mã khác thay đổi nó:
Thí dụ
// Initiate counter
let counter = 0;
// Function to increment
counter
function add() {
let counter = 0;
counter += 1;
}
//
Call add() 3 times
add();
add();
add();
//The counter should
now be 3. But it is 0
Nó không hoạt động vì chúng tôi hiển thị bộ đếm toàn cục thay vì bộ đếm cục bộ.
Chúng ta có thể xóa bộ đếm toàn cục và truy cập bộ đếm cục bộ bằng cách cho phép hàm trả về bộ đếm đó:
Thí dụ
// Function to increment
counter
function add() {
let counter = 0;
counter += 1;
return counter;
}
//
Call add() 3 times
add();
add();
add();
//The counter should
now be 3. But it is 1.
Nó không hoạt động vì chúng tôi đặt lại bộ đếm cục bộ mỗi khi chúng tôi gọi hàm.
Một hàm bên trong JavaScript có thể giải quyết điều này.
Các hàm lồng nhau trong JavaScript
Tất cả các chức năng đều có quyền truy cập vào phạm vi toàn cầu.
Trên thực tế, trong JavaScript, tất cả các hàm đều có quyền truy cập vào phạm vi "bên trên" chúng.
JavaScript hỗ trợ các hàm lồng nhau. Các hàm lồng nhau có quyền truy cập vào phạm vi "phía trên" chúng.
Trong ví dụ này, hàm bên trong plus()
có quyền truy cập vào counter
biến trong hàm mẹ:
Thí dụ
function add() {
let counter = 0;
function plus() {counter += 1;}
plus();
return counter;
}
Điều này có thể giải quyết được tình thế tiến thoái lưỡng nan, nếu chúng ta có thể tiếp cận plus()
chức năng từ bên ngoài.
Chúng ta cũng cần tìm cách thực thi counter = 0
một lần duy nhất.
Chúng tôi cần đóng cửa.
JavaScript Closures
Nhớ các chức năng tự gọi? Chức năng này làm gì?
Thí dụ
const add = (function () {
let counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add();
// the counter is now 3
Giải thích ví dụ
Biến add
được gán cho giá trị trả về của một hàm tự gọi.
Chức năng tự gọi chỉ chạy một lần. Nó đặt bộ đếm thành không (0) và trả về một biểu thức hàm.
Bằng cách này, add trở thành một hàm. Phần "tuyệt vời" là nó có thể truy cập bộ đếm trong phạm vi cha.
Đây được gọi là một JavaScript đóng. Nó làm cho một hàm có thể có các biến " riêng tư ".
Bộ đếm được bảo vệ bởi phạm vi của chức năng ẩn danh và chỉ có thể được thay đổi bằng cách sử dụng chức năng thêm.
Đóng là một hàm có quyền truy cập vào phạm vi cha, ngay cả sau khi hàm cha đã đóng.