Mất ngữ cảnh trong JavaScript
Giả sử chúng ta có một hàm bên trong hàm. Hãy
gọi hàm bên ngoài là parent, còn
hàm bên trong là child:
function parent() {
function child() {
}
}
Từ các bài học trước, bạn đã biết rằng nếu đặt bất kỳ biến nào trong hàm bên ngoài - nó sẽ có thể truy cập được từ hàm bên trong:
function parent() {
let str = 'abcde';
function child() {
console.log(str); // sẽ in ra 'abcde'
}
child(); // gọi hàm bên trong
}
parent(); // gọi hàm bên ngoài
Tuy nhiên, có một điểm cần lưu ý: hàm bên trong có
quyền truy cập vào tất cả các biến của hàm bên ngoài, nhưng không
có quyền truy cập vào this. Tức là: nếu
hàm bên ngoài được ràng buộc với một phần tử DOM
nào đó, thì this trong nó sẽ trỏ
đến phần tử đó, nhưng this của hàm
bên trong - sẽ không trỏ đến!
Vậy this của hàm bên trong sẽ trỏ
đến cái gì? Câu trả lời: nó sẽ bằng
undefined (trong chế độ nghiêm ngặt), bởi
vì hàm không được ràng buộc với bất cứ thứ gì.
Hãy kiểm tra trong thực tế. Giả sử chúng ta có một ô nhập liệu:
<input id="elem" value="text">
Hãy ràng buộc hàm parent vào ô nhập liệu này,
hàm sẽ được gọi khi ô nhập liệu mất tiêu điểm:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
// Sẽ được gọi khi mất tiêu điểm:
function parent() {
// ở đây sẽ có một số mã
function child() {
// ở đây sẽ có một số mã
}
child(); // gọi hàm con
}
Hãy in nội dung của this ra
console ở hai vị trí: bên trong hàm parent
và bên trong hàm child:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this); // sẽ in ra tham chiếu đến ô nhập liệu của chúng ta
function child() {
console.log(this); // sẽ in ra undefined
}
child();
}
Chạy mã này, làm cho ô nhập liệu mất tiêu điểm
và xem trong console - bạn sẽ thấy rằng
console.log đầu tiên sẽ in ra console
tham chiếu đến ô nhập liệu của chúng ta, còn cái thứ hai - chỉ là undefined.
Tình huống như vậy, khi this một cách
không ngờ tới lại không trỏ đến thứ chúng ta
cần, được gọi là mất ngữ cảnh.
Bây giờ giả sử trong cả hai hàm
chúng ta sẽ in ra value của ô nhập liệu. Hãy xác định,
điều gì sẽ được in ra trong các dòng mã, được đánh dấu
bằng chú thích:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this.value); // sẽ in ra gì?
function child() {
console.log(this.value); // sẽ in ra gì?
}
child();
}