Họ đang đo gì
Bạn có biết this phụ thuộc vào CÁCH GỌI chứ không phải nơi định nghĩa, và biết khi nào điều đó gây bug.
Trả lời ngắn~30 giây
Xét theo thứ tự: new thì this là object vừa tạo; call/apply/bind thì this là thứ bạn truyền; gọi như phương thức obj.fn() thì this là obj; còn lại thì là undefined ở strict mode hoặc global object ở sloppy mode. Arrow function không tham gia: nó lấy this từ scope bao ngoài lúc định nghĩa, và bind không đổi được.
Giải thích sâu
Bug kinh điển là mất this khi truyền phương thức đi làm callback: setTimeout(obj.method, 0) gọi hàm mà không có object phía trước, nên this không còn là obj. Ba cách sửa: bind lúc truyền, bọc trong arrow function, hoặc khai báo thẳng thuộc tính là arrow function trong class. Mỗi cách có chi phí khác nhau — bind tạo hàm mới mỗi lần gọi, nên trong React nó là nguyên nhân re-render không cần thiết.
Điểm ngược lại cũng quan trọng: arrow function KHÔNG dùng được làm phương thức của object khi bạn cần this trỏ vào object đó, và không dùng được làm hàm khởi tạo. Nó cũng không có arguments. Nên câu trả lời tốt không phải “arrow function tốt hơn” mà là “arrow function giải quyết đúng bài toán mất ngữ cảnh, và tạo ra bài toán khác nếu dùng sai chỗ”.
const timer = {
seconds: 0,
startBroken() {
setInterval(function () { this.seconds++; }, 1000);
// `this` là undefined (strict) — hàm được gọi trần
},
startWorking() {
setInterval(() => { this.seconds++; }, 1000);
// arrow lấy `this` của startWorking, tức là `timer`
},
};
const { startWorking } = timer;
startWorking(); // vẫn hỏng: mất object phía trước khi gọiCâu hỏi tiếp theo họ sẽ hỏi
?call, apply, bind khác nhau ra sao?
call và apply gọi ngay, khác nhau ở cách truyền tham số (rời và mảng). bind không gọi mà trả về hàm mới đã gắn this — và gắn rồi thì không đổi lại được, bind lần hai vô tác dụng.
Trả lời thế này là mất điểm
- Nói “
thislà object hiện tại”. Không có “object hiện tại” — chỉ có cách hàm được gọi.