Scenario
Giả sử ta có một object như sau:
// global scope
this.name = "Charmander"
const pikachu = {
name: "Pikachu",
sleep(time = 1) {
console.log(`${this.name} is sleeping for ${time} hour(s)`)
},
}
pikachu.sleep() // Pikachu is sleeping for 1 hour(s)
const pikachuSleep = pikachu.sleep
pikachuSleep() // Charmander is sleeping for 1 hour(s)Có thể thấy, biến name khai báo ở đầu chính là của đối tượng window, mang global scope.
Khi chúng ta gọi phương thức sleep thông qua đối tượng pikachu, từ khóa this sẽ trỏ đến đối tượng pikachu.
Tuy nhiên, khi gán phương thức này cho biến pikachuSleep, rồi ta gọi biến pikachuSleep này, this sẽ trỏ đến window object do không được gọi thông qua bất kỳ đối tượng nào (tham khảo JS this Keyword).
Việc gán một phương thức cho một biến thường rất hay xảy ra, bởi vì việc gọi phương thức từ đối tượng đôi khi rất cồng kềnh.
Binding this Keyword
Để ràng buộc this với một đối tượng cụ thể, chúng ta sẽ phải sử dụng phương thức bind với đối số là đối tượng cần ràng buộc.
const pikachuSleep = pikachu.sleep.bind(pikachu)
pikachuSleep() // Pikachu is sleeping for 1 hour(s)Phương thức bind có sẵn đối với mọi hàm khi chúng được tạo ra.
Nếu chúng ta tạo ra thêm một đối tượng khác, cũng có thể ràng buộc this đến đối tượng đó:
const bulbasaur = {
name: "Bulbasaur",
}
const bulbasaurSleep = pikachu.sleep.bind(bulbasaur)
bulbasaurSleep() // Bulbasaur is sleeping for 1 hour(s)Properties of Bind Method
Phương thức bind sẽ trả về một hàm mới.
const bulbasaurSleep = pikachu.sleep.bind(bulbasaur)
console.log(pikachu.sleep === bulbasaurSleep) // falseMethod nhận lại sau khi ràng buộc cũng có thể truyền vào các đối số như bình thường:
const pikachuSleep = pikachu.sleep.bind(pikachu)
pikachuSleep(10) // Pikachu is sleeping for 10 hour(s)Trong trường hợp ta chắc chắn rằng đối số truyền vào phương thức sleep ít bị thay đổi, ta có thể truyền thẳng đối số đó vào phương thức bind.
const pikachuSleep = pikachu.sleep.bind(pikachu, 10)
pikachuSleep(8) // Pikachu is sleeping for 10 hour(s)Đối số truyền vào hàm pikachuSleep lúc sau sẽ không được ưu tiên.
Bind Method as an Event Function
Giả sử ta có một nút trong HTML như sau:
<button>Sleep</button>Ta có đối tượng pikachu như sau:
const pikachu = {
name: "Pikachu",
type: "electric",
getInfo() {
console.log(`${this.name} has ${this.type} type`)
},
}Thêm sự kiện vào nút bấm:
const button = document.querySelector("button")
button.onclick = function () {
pikachu.getInfo()
}Do onclick có giá trị là một hàm, ta có thể viết đoạn code trên ngắn gọn lại như sau:
button.onclick = pikachu.getInfoTuy nhiên, từ khóa this của phương thức getInfo lại tham chiếu đến đối tượng button, vốn không có thuộc tính name và type. Do đó, ta cần ràng buộc từ khóa this vào đối tượng pikachu:
button.onclick = pikachu.getInfo.bind(pikachu) // Pikachu has electric typeBind Method for querySelector
Việc dùng phương thức document.querySelector lặp đi lặp lại nhiều lần là rất cồng kềnh.
Chúng ta có thể sử dụng phương thức bind để tối giản công việc đó như sau:
<h1 class="title">Hello world</h1>const $ = document.querySelector.bind(document)
const title = $(".title")
console.log(title.innerText) // Hello worldTheo đoạn code trên, ta gán phương thức querySelector sau khi ràng buộc nó với đối tượng document để có thể sử dụng nhiều lần chỉ với một biến đơn giản ($).