Trong JavaScript, this
là một từ khóa đặc biệt, đại diện cho ngữ cảnh hiện tại của hàm hoặc đối tượng. Cụ thể, this
thường tham chiếu đến đối tượng mà hàm đang được gọi từ nó, nhưng giá trị của this
có thể thay đổi tùy thuộc vào cách hàm được gọi.
Cách hoạt động của this
:
1. Trong phương thức của đối tượng
Khi bạn gọi một phương thức trên một đối tượng, this
bên trong phương thức sẽ tham chiếu đến đối tượng đó.
const person = {
name: 'Alice',
greet: function() {
console.log(this.name); // 'this' ở đây là đối tượng 'person'
}
};
person.greet(); // Kết quả: 'Alice'
2. Trong một hàm thông thường
Trong một hàm thông thường, this
tham chiếu đến global object (trong trình duyệt là đối tượng window
), nhưng trong chế độ strict mode ("use strict"
), this
sẽ là undefined
.
function showName() {
console.log(this); // Trong trình duyệt, this sẽ là window
}
showName();
3. Trong hàm constructor
Khi bạn sử dụng hàm khởi tạo (constructor function
), this
sẽ tham chiếu đến đối tượng mới được tạo ra từ constructor đó.
function Car(brand) {
this.brand = brand;
}
const myCar = new Car('Toyota');
console.log(myCar.brand); // 'Toyota'
4. Trong các sự kiện DOM
Khi một sự kiện DOM được kích hoạt, this
thường tham chiếu đến phần tử mà sự kiện đó được gán.
const button = document.querySelector('button');
button.addEventListener('click', function() {
console.log(this); // 'this' ở đây là phần tử 'button'
});
5. Arrow function
Trong arrow function, this
không bị ràng buộc theo cách truyền thống mà nó kế thừa giá trị của this
từ phạm vi cha gần nhất của nó.
const person = {
name: 'Alice',
greet: function() {
const innerGreet = () => {
console.log(this.name); // 'this' kế thừa từ 'person'
};
innerGreet();
}
};
person.greet(); // Kết quả: 'Alice'
6. Sử dụng call
, apply
, và bind
Bạn có thể sử dụng các phương thức call
, apply
, và bind
để thiết lập rõ ràng giá trị của this
khi gọi một hàm.
call
cho phép bạn gọi một hàm với một đối tượng cụ thể làm giá trị của this
.
function show() {
console.log(this.name);
}
const obj = { name: 'Alice' };
show.call(obj); // Kết quả: 'Alice'
apply
cũng tương tự như call
, nhưng bạn truyền đối số dưới dạng mảng.
function introduce(greeting) {
console.log(greeting + ', my name is ' + this.name);
}
const obj = { name: 'Alice' };
introduce.apply(obj, ['Hello']); // Kết quả: 'Hello, my name is Alice'
bind
tạo ra một hàm mới với this
được thiết lập.
function show() {
console.log(this.name);
}
const obj = { name: 'Alice' };
const boundShow = show.bind(obj);
boundShow(); // Kết quả: 'Alice'
7. Trong các lớp (Classes)
Trong JavaScript ES6, khi bạn sử dụng lớp (class), this
cũng tham chiếu đến đối tượng của lớp.
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(this.name);
}
}
const alice = new Person('Alice');
alice.greet(); // Kết quả: 'Alice'
8. Tình huống trong Promise
Trong các hàm xử lý Promise
, giá trị của this
cũng có thể không như mong đợi.
const obj = {
name: 'Alice',
greet: function() {
return new Promise((resolve) => {
resolve(this.name); // 'this' không được kế thừa từ obj
});
}
};
obj.greet().then((name) => console.log(name)); // Kết quả: 'Alice' trong bối cảnh đúng
9. Lưu ý khi sử dụng this
Mặc dù this
là một phần quan trọng trong JavaScript, nhưng có một số lưu ý mà bạn cần ghi nhớ để tránh những vấn đề tiềm ẩn trong quá trình phát triển:
a. Tránh sử dụng this
trong callback
Khi bạn truyền một hàm như là một callback, giá trị của this
có thể không phải là bạn mong đợi. Để khắc phục, bạn có thể sử dụng phương pháp bind
, hoặc sử dụng arrow functions để giữ nguyên ngữ cảnh.
const obj = {
name: 'Alice',
greet: function() {
setTimeout(function() {
console.log(this.name); // 'this' ở đây không phải là 'obj'
}, 1000);
}
};
obj.greet(); // Kết quả: undefined
// Sửa bằng cách sử dụng bind
const objWithBind = {
name: 'Alice',
greet: function() {
setTimeout(function() {
console.log(this.name);
}.bind(this), 1000); // Sử dụng bind để giữ giá trị của 'this'
}
};
objWithBind.greet(); // Kết quả: 'Alice'
// Hoặc dùng arrow function
const objWithArrow = {
name: 'Alice',
greet: function() {
setTimeout(() => {
console.log(this.name); // 'this' ở đây là 'objWithArrow'
}, 1000);
}
};
objWithArrow.greet(); // Kết quả: 'Alice'
b. Sử dụng Strict Mode
Khi sử dụng strict mode trong JavaScript ("use strict"
), this
trong hàm sẽ trở thành undefined
nếu không có ngữ cảnh. Điều này có thể giúp bạn phát hiện lỗi.
"use strict";
function show() {
console.log(this); // Kết quả: undefined
}
show();
c. Sự khác biệt giữa phương thức và hàm thông thường
Khi bạn gọi một phương thức từ một đối tượng, this
sẽ tham chiếu đến đối tượng đó. Nhưng khi bạn gọi một hàm thông thường, this
sẽ là đối tượng toàn cầu (trong trình duyệt là window
), điều này có thể gây nhầm lẫn nếu không hiểu rõ.
d. Lưu ý với đối tượng toàn cầu
Khi gọi một hàm mà không có ngữ cảnh, this
sẽ trỏ đến đối tượng toàn cầu, vì vậy hãy cẩn thận khi bạn cần sử dụng this
trong các hàm.
function globalFunc() {
console.log(this); // Trỏ đến window trong trình duyệt
}
globalFunc();
e. Tổ chức mã hiệu quả
Hãy cố gắng tổ chức mã của bạn sao cho giá trị của this
luôn rõ ràng. Sử dụng các phương thức như bind
, call
, hoặc apply
một cách hợp lý để thiết lập giá trị cho this
và tránh sự nhầm lẫn trong quá trình phát triển.
f. Kiểm tra với console.log(this)
Đôi khi, cách tốt nhất để hiểu cách hoạt động của this
là thử nghiệm và xem kết quả bằng cách sử dụng console.log(this)
trong các ngữ cảnh khác nhau.
function checkThis() {
console.log(this);
}
const obj1 = {
name: 'Alice',
method: checkThis
};
const obj2 = {
name: 'Bob'
};
obj1.method(); // 'this' là obj1
checkThis(); // 'this' là window (trong trình duyệt)
checkThis.call(obj2); // 'this' là obj2
10. Kết luận
Hiểu cách hoạt động của this
trong JavaScript là rất quan trọng để xây dựng ứng dụng hiệu quả. Bằng cách nắm rõ các quy tắc và lưu ý về this
, bạn có thể tránh được nhiều lỗi phổ biến và làm cho mã của mình dễ bảo trì và mở rộng hơn. Hãy thực hành thường xuyên và thử nghiệm trong các tình huống khác nhau để làm quen với hành vi của this
.