綁定物件的方法
javascript 中一個設計是,物件的方法是不綁定的, 當要傳遞物件的方法時,會失去對物件的綁定, 只會傳入一個半完成沒有 this 的方法。 除了在傳遞方法時手動用 bind 綁定, 也能在建物實例時,手動綁定。 或把 bind 的過程隱藏在 getter 中,來做存取時綁定, 或直接為物件新增一個 bind 方法。
物件綁定方法或方法綁定物件
javascript 的函數有 bind 方法, 可以把一個函數綁到某一個物件上。 一般會在要把物件方法當回呼函數傳遞時, 把方法 bind 到物件上。
// 只傳了 remove 函數,沒有傳入 button
button.addEventListener('click', button.remove)
// bind 一個方法寫起來很長
button.addEventListener('click', button.remove.bind(button))
但這樣 bind 寫起來很長不太方便, 於是可以為物件新增一個方法, 可以返回該物件上綁好的方法。 從原本把函數綁到物件上, 變成把已經屬於物件的方法再綁定。
Object.prototype.bindMethod = function (method) {
if (typeof method == 'function') return method.bind(this)
else return this[method].bind(this)
}
button.addEventListener('click', button.bindMethod('remove'))
這樣寫起來就比較短。 而且還玩了一個小把戲, 如果傳入的是函數,就直接綁定。 可以選擇傳入屬性名或直接傳入方法。
用 getter 返回綁定的方法
物件的方法也可以是一個返回函數的 getter, 如果在每次 get 時都把方法先綁定再返回, 就可以達到效果。
const object = {
name: 'obj',
_say(sentence) {
console.log(`${this.name}: ${sentence}`)
},
get say() {
return this._say.bind(this)
// 或直接用上面定義的 bindMethod 方法
// return this.bindMethod('_say')
}
}
這裡是在要在存取時綁定, 就是不用傳遞回呼函數時綁定, 變成每次存取時都回傳一個已經綁定好的函數。
// 存取 say 屬性時,就直接返回一個綁定了的函數
button.addEventListener('click', object.say)
// 不用再手動綁定
// button.addEventListener('click', object._say.bind(object))
如果用 class 定義成物件原型的 getter, 就可以每個實例都繼承到 getter, 每個實例在存取 getter 時都是 bind 到該實例上。 而不用在構造成實例時,手動把方法綁定。
class Obj {
constructor(name) {
this.name = name
// 在構造時就把所有方法都綁定
this.say = this.say.bind(this)
this.bye = this.bye.bind(this)
}
say(sentence) {
console.log(`${this.name}: ${sentence}`)
}
bye() {
this.say('bye')
}
}
getter 返回未綁定的函數
另外一點蠻有趣,如果 getter 是返回一個函數, 那該函數的 this 也是指向 getter 的所屬物件。
function showThisName() {
console.log(this.name)
}
const object = {
get getShowThisName() {
return showThisName
},
name: 'obj'
}
object.getShowThisName == showThisName
object.getShowThisName() // obj
這點還沒有想到什麼應用,只是覺得很有趣而已。