this không phụ thuộc nơi hàm được định nghĩa mà phụ thuộc cách hàm được gọi.
Bốn quy tắc, xét theo thứ tự ưu tiên giảm dần:
javascript
function show() { console.log(this?.tag) }
// 1. new binding — this là object vừa tạo
function User(tag) { this.tag = tag }
new User('mới').tag // 'mới'
// 2. explicit binding — call / apply / bind
show.call({ tag: 'explicit' }) // 'explicit'
// 3. implicit binding — gọi qua object
const obj = { tag: 'implicit', show }
obj.show() // 'implicit'
// 4. default binding — không thuộc ba trường hợp trên
show() // undefined — this là undefined (strict) hoặc globalThis (sloppy), cả hai đều không có .tagArrow function không nằm trong bốn quy tắc này — nó không có this riêng mà lấy từ scope bao ngoài lúc định nghĩa, và call/bind không đổi được.
javascript
const arrow = () => console.log(this)
arrow.call({ tag: 'x' }) // vẫn là this của scope ngoàiLưu ý — mất this khi tách method ra khỏi object:
javascript
const timer = { sec: 0, tick() { this.sec++ } }
setInterval(timer.tick, 1000) // SAI — this là window (browser) / Timeout (Node), không phải timer
setInterval(() => timer.tick(), 1000) // đúng
setInterval(timer.tick.bind(timer), 1000) // đúngChốt: nhìn vào dấu chấm bên trái lời gọi là ra this trong hầu hết trường hợp.
Không có dấu chấm và không new/call thì rơi vào default binding.