Bộ hẹn giờ và mất ngữ cảnh trong JavaScript
Khi sử dụng bộ hẹn giờ trong trình xử lý sự kiện, chúng ta có thể gặp phải vấn đề mất ngữ cảnh. Hãy xem xét qua ví dụ.
Giả sử chúng ta có một phần tử input:
<input id="elem" value="text">
Giả sử khi nhấp vào phần tử input này, một hàm ẩn danh sẽ được thực thi và bên trong hàm đó, một bộ hẹn giờ sẽ được khởi động, mỗi giây in ra thứ gì đó vào console:
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
console.log('!!!'); // in thứ gì đó ra console
}, 1000);
});
Mọi thứ vẫn hoạt động đúng cho đến nay. Nhưng giả sử bây giờ
chúng ta muốn in giá trị value
của phần tử input ra console - chúng ta sẽ gặp bất ngờ: trong console
sẽ in ra undefined:
elem.addEventListener('click', function() {
setInterval(function() {
console.log(this.value); // sẽ in ra undefined
}, 1000);
});
Vấn đề nằm ở chỗ chúng ta có một hàm bên trong một hàm:
có một hàm ẩn danh bên ngoài,
được gọi khi nhấp chuột và một hàm ẩn danh bên trong,
được bộ hẹn giờ gọi.
Trong hàm bên ngoài, this trỏ
đến phần tử input, nhưng trong hàm bên trong thì không. Đây là hiện tượng
mất ngữ cảnh.
Tại sao lại in ra undefined, mà không báo
lỗi trong console, như trong các bài học trước?
Bởi vì this bên trong hàm,
được gọi thông qua setInterval, trỏ
đến window.
Điều này có nghĩa là chúng ta đang cố gắng đọc thuộc tính
value của đối tượng window, như thế này: window.value,
mà trong nó không có thuộc tính nào như vậy, và chúng ta nhận được
undefined (không phải lỗi).
Hãy sửa vấn đề bằng cách sử dụng self:
elem.addEventListener('click', function() {
let self = this;
setInterval(function() {
console.log(self.value);
}, 1000);
});
Giả sử có đoạn mã sau:
<input type="button" id="elem" value="1">
let elem = document.querySelector('#elem');
elem.addEventListener('click', function() {
setInterval(function() {
this.value = Number(elem.value) + 1;
}, 1000);
});
Tác giả đoạn mã muốn rằng khi nhấn vào nút,
giá trị của nút đó sẽ tăng lên
1 mỗi giây.
Tuy nhiên, khi nhấn vào nút
không có gì xảy ra. Hãy sửa lỗi
của tác giả đoạn mã. Viết một văn bản trong đó bạn
giải thích cho tác giả đoạn mã tại sao lại xảy ra
lỗi của anh ta.