简体   繁体   中英

Automatic _.bindAll() in backbone.js

Is there a way to automatically do an _.bindAll for a backbone.js object?

I was talking to someone a while ago and they said that there was, but I have no idea where to start looking.

Example:

var TheView = Backbone.View.extend({

    initialize: function() {
        // HOW CAN I AVOID HAVING TO DO THIS?---->
        _.bindAll(this,'render','on_element_01_click', 'on_element_02_click');
    },

    events: {
        'click #element_01': 'on_element_01_click',
        'click #element_02': 'on_element_02_click',
    },

    render: function(){
        return this;
    },

    on_element_01_click: function(){

    },

    on_element_02_click: function(){

    }
}

Do this instead:

_.bindAll(this);

Will bind ALL functions in this view.

I've since learned of a easier technique if you want to build bindAll in to your views (which is handy for things like AJAX callback methods that aren't auto-bound the way event handlers are). Basically you just override the constructor to perform the auto-binding.

var BoundModel = Backbone.Model.extend({
    constructor: function() {
        Backbone.Model.apply(this, arguments);
        if (this.boundMethods) {
            _(this).bindAll.apply(this, this.boundMethods);
        }
    }
})

var SubclassOfBoundModel = Backbone.Model.extend({
     boundMethods: ['handleFetchResponse'],
     initialize: function () {
         this.model.on('sync', this.handleFetchResponse);
     }
     handleFetchResponse: function() {
         // this function is bound to the model instance
     }
})

Of course if you just wanted to bind all your methods you could leave out the "boundMethods" part and just have:

    constructor: function() {
        Backbone.Model.apply(this, arguments);
        _(this).bindAll();
    }

I tried doing this myself and I was able to get it working with something like this:

function bindOnExtend(clazz) {
    var originalExtend = clazz.extend;
    clazz.extend = function() {
        var newSubClass = originalExtend.apply(this, arguments);
        var originalInitialize = newSubClass.prototype.initialize;
        newSubClass.prototype.initialize = function() {
            // The constructor will get broken by bindAll; preserve it so _super keeps working
            var realConstructor = this.constructor;
            _.bindAll(this);
            this.constructor = realConstructor;
            originalInitialize.apply(this, arguments);
        };
        return bindOnExtend(newSubClass);
    };
    return clazz;
}

var BoundModel = Backbone.Model.extend();
bindOnExtend(BoundModel);

var BoundView = Backbone.View.extend();
bindOnExtend(BoundView);

However, I wouldn't recommend it. Doing that will make closures for every single method on every single model/view/whatever you instantiate. Not only does that add a slight increase in overall memory usage, it also opens up the possibility of memory leaks if you're not careful. Furthermore, it makes your stacktraces several lines longer, as they have to wind through bindOnExtend.

In my experience, having to do " _.bindAll(this, ... " is worth the trouble because:

1) it makes my code more clear/obvious to anyone coming after me 2) it encourages me to qualify my bindAll , instead of just using the 1-arg form 3) I hate wading through long stacktraces

But, if you want it the above code should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM