backbonebackbone

之前寫了一篇 Backbone.js Event 事件介紹,簡介 Backbone.js Events 如何使用 onoff 來處理事件,在升級 Backbone 到 0.9.9 過程中,其中一項重大新功能就是 Backbone listenTo and stopListening,大家來看看 Change logs:

Added listenTo and stopListening to Events. They can be used as inversion-of-control flavors of on and off, for convenient unbinding of all events an object is currently listening to. view.remove() automatically calls view.stopListening().


如果大家想更了解 listenTo and stopListening 可以直接看國外這篇 Managing Events As Relationships, Not Just References,或者是看看此 commit log,裡面詳細介紹為什麼 Backbone 會增加此功能,其實最主要的重點是以前在 Backbone View 寫法都是像底下這樣

initialize: function() {
    if (this.model) {
        this.model.on("change", this.render, this);
    }
},

render: function () {

}

上面我們可以看到當 model 有任何改變時,就會 trigger render function,這是最簡單的寫法,當我們移除 View 的時候,此事件就會跟著消失,但是如果是 Reference 到其他 Object 物件方法,如底下

myObject.on("some:event", anotherObject.someHandler);

當 anotherObject 物件被移除時,這時 myObject 還是綁定事件在 anotherObject 上面,這就會出現 zombie objects in JavaScript apps,當然這是有解法的,我們只需要在移除 anotherObject 之前呼叫底下程式碼:

myObject.off("some:event", anotherObject.someHandler);

透過上面解法,我們可以將 Backbone.js View 寫法改成底下:

Backbone.View.extend({

    initialize: function(){
        this.model.on("change:foo", this.doStuff, this);
    },

    doStuff: function(foo){
        // do stuff in response to "foo" changing
    },

    remove: function(){
        this.model.off("change:foo", this.doStuff, this);

        // call the base type's method, since we are overriding it
        Backbone.View.prototype.remove.call(this);
    }

})

Backbone.js View Remove 改寫如下

remove: function(){
    this.model.off("change:foo", this.doStuff, this);

    // call the base type's method, since we are overriding it
    Backbone.View.prototype.remove.call(this);
}

這樣就可以解決僵屍事件,但是如果有十個事件,那在 remove 裏面就會寫的很雜,所以在 0.9.9 版本出現 listenTo 和 stopListening 來解決此問題。程式碼改成如下

Backbone.View.extend({

    initialize: function(){
        this.listenTo(this.model, "change:foo", this.doStuff);
    },

    doStuff: function(foo){
        // do stuff in response to "foo" changing
    }

    // we don't need this. the default `remove` method calls `stopListening` for us
    // remove: function(){
        // this.stopListening();
        // ...
    //}
})

注意四大要點

1. 在 Backbone.View 裡面改用 listenTo 寫法
2. 將 this.model 傳入 listenTo function
3. 不用傳入最後一個參數 this 當作 context 變數
4. 不需要再 override Backbone.View 的 remove function 了,因為在程式碼裏面就會自動呼叫 this.stopListening()

所以以後不要在寫 this.model.on 了,請全面改寫成 this.listenTo(this.model, ..) 寫法。