this trong JavaScript là từ khóa tham chiếu đến **object mà hàm đang được thực thi thuộc về**. Giá trị của this được xác định tại **thời điểm gọi hàm (runtime)**, không phải tại nơi định nghĩa.
Quy tắc xác định this (theo thứ tự ưu tiên):
| Loại gọi | Cú pháp | Giá trị this | Ví dụ |
|---|---|---|---|
| New binding | new Fn() | Instance mới tạo | new Person() |
| Explicit binding | fn.call(obj), fn.apply(obj), fn.bind(obj) | Object truyền vào | fn.call(user) |
| Implicit binding | obj.method() | Object chứa method | user.greet() |
| Default binding | fn() (standalone) | Global object (window) hoặc undefined (strict mode) | greet() |
| Arrow function | () => {} | Lexical this (kế thừa từ scope bên ngoài) | const fn = () => this |
Ví dụ minh họa
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript this Keyword</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
.sample { font-size: 18px; font-weight: 500; margin: 10px 0; color: red; }
.result { font-size: 18px; font-weight: 500; margin: 10px 0; color: green; }
button { padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>JavaScript this Keyword</h1>
<div class="sample" id="sample"></div>
<div class="result" id="result"></div>
<button class="Btn" id="btn">NHẤN VÀO ĐÂY</button>
<h3> Nhấn nút để xem 'this' tham chiếu đến object nào trong các ngữ cảnh </h3>
<script>
const sampleEle = document.querySelector("#sample");
const resEle = document.querySelector("#result");
// 1. Default binding (global/undefined)
const globalThis = this; // window (non-strict) hoặc undefined (strict)
// 2. Function declaration - default binding
function regularFunction() {
return this;
}
// 3. Method trong object - implicit binding
const testObj = {
a: 22,
check() {
return this; // this = testObj
}
};
// 4. Arrow function - lexical this
const arrowFn = () => this; // this = globalThis (window)
// 5. Event handler - this = element nhận event
document.querySelector("#btn").addEventListener("click", function() {
sampleEle.innerHTML = "";
// Default binding
sampleEle.innerHTML += "Hàm thường (default binding): " + regularFunction() + "
";
// Implicit binding
sampleEle.innerHTML += "Method trong object (implicit): " + testObj.check() + "
";
// Global this
sampleEle.innerHTML += "This toàn cục: " + globalThis + "
";
// Arrow function
sampleEle.innerHTML += "Arrow function (lexical): " + arrowFn() + "
";
// Event handler - this = button element
sampleEle.innerHTML += "Event handler (this = button): " + this.tagName + "#" + this.id + "
";
// call/apply/bind demo
function greet(greeting, punctuation) {
return `${greeting}, ${this.name}${punctuation}`;
}
const user = { name: "Rohan" };
resEle.innerHTML = "call(): " + greet.call(user, "Xin chào", "!") + "
";
resEle.innerHTML += "apply(): " + greet.apply(user, ["Chào", "."]) + "
";
const boundGreet = greet.bind(user, "Hello");
resEle.innerHTML += "bind(): " + boundGreet("?") + "
";
});
</script>
</body>
</html>
Kết quả
Khi nhấn nút, hiển thị this trong các ngữ cảnh khác nhau:
- Hàm thường (standalone):
window(hoặcundefinedstrict mode) - Method trong object: object chứa method (
testObj) - Arrow function: kế thừa
thistừ scope bên ngoài (global) - Event handler: element nhận event (
button) call/apply/bind: object được truyền vào
Các lỗi thường gặp & cách khắc phục:
// ❌ Mất this trong callback
const obj = {
name: "JS",
logName() {
setTimeout(function() {
console.log(this.name); // undefined (this = window)
}, 100);
}
};
// ✅ Sửa: Arrow function (lexical this)
setTimeout(() => console.log(this.name), 100);
// ✅ Sửa: bind
setTimeout(function() { console.log(this.name); }.bind(this), 100);
// ✅ Sửa: lưu this vào biến
const self = this;
setTimeout(function() { console.log(self.name); }, 100);
Tóm tắt: this phụ thuộc vào cách hàm được gọi, không phải nơi định nghĩa. Arrow function không có this riêng - kế thừa từ scope bao quanh.