var
hoặc thậm chí khi xử lý biến ngoài vòng lặp.generateShooter
là một hàm tạo closure đóng gói tham số number
. Vòng lặp while
được dùng để tạo từng shooter function và đẩy vào mảng.army[0]()
, ta mong đợi xuất ra số 0
, army[1]()
ra 1
,... Nhưng trong một số trường hợp, kết quả lại in ra 10
cho tất cả các shooters, tức là số cuối cùng của vòng lặp.var
, nó có phạm vi function nên tất cả closures cùng tham chiếu đến một biến chung.let
trong while
, hành vi có thể khác nhau tùy phiên bản công cụ và browser.for
?while
, vòng lặp for
trong JavaScript với từ khóa let
khai báo biến lặp giúp tạo ra một phạm vi mới cho mỗi vòng lặp. Điều này nghĩa là mỗi biến i
trong vòng for
được coi là một biến độc lập, riêng biệt trong từng vòng, nên closure sẽ lưu giữ giá trị đúng.function makeArmy() { let shooters = [];
for (let i = 0; i < 10; i++) { let shooter = function() { console.log(i); }; shooters.push(shooter); }
return shooters;}
let army = makeArmy();
army[0](); // 0army[1](); // 1army[2](); // 2
let i
trong vòng for
là một biến mới trong từng lượt lặp, đảm bảo closure giữ đúng giá trị.shooter
khi gọi sẽ lấy chính giá trị i
thu tại vòng lặp tương ứng.while
sang for
với let
là cách đơn giản, trực quan và hiệu quả để giải quyết vấn đề closure quấn tham chiếu biến lặp.generateShooter(number)
gói lại biến tham số riêng biệt:function makeArmy() { let shooters = [];
function generateShooter(number) { return function() { console.log(number); }; }
let i = 0; while (i < 10) { shooters.push(generateShooter(i)); i++; }
return shooters;}
function makeArmy() { let shooters = [];
for (var i = 0; i < 10; i++) { (function(number) { shooters.push(function() { console.log(number); }); })(i); }
return shooters;}
Phương pháp này tạo một phạm vi mới bằng cách chạy hàm ngay lập tức, giữ nguyên giá trị biến number
.
Cách làm | Ưu điểm | Nhược điểm |
---|---|---|
Vòng lặp for + let | Code ngắn gọn, dễ hiểu | Cần ES6 trở lên |
Hàm tạo closure riêng | Dễ kiểm soát và mở rộng | Cần thêm hàm trung gian |
IIFE | Tương thích ES5, vận hành tốt trên trình cũ | Code có thể phức tạp hơn |
while
, nhờ đó giữ được tham số chính xác cho từng function trong mảng.“Javascript.info là một trong những website tốt nhất giúp bạn hiểu rõ các khái niệm JS với phương pháp học qua thực hành, đặc biệt đối với những phần như closure.”
let
trong vòng lặp for
hoặc tạo ra closure riêng biệt. Bạn nên luyện tập nhiều vấn đề tương tự để thành thạo.