When do I need to use _.bindAll() in Backbone.js?

2020-02-25 04:45发布

问题:

I am learning backbone.js, and feel confused on this: I am following the tutorial : http://arturadib.com/hello-backbonejs/

as you can see in the first example (1.js):

(function($){
  var ListView = Backbone.View.extend({    
    el: $('body'), // attaches `this.el` to an existing element.

    initialize: function(){
      _.bindAll(this, 'render'); // fixes loss of context for 'this' within methods

       this.render(); // not all views are self-rendering. This one is.
    },

    render: function(){
      $(this.el).append("<ul> <li>hello world</li> </ul>");
    }
  });

  var listView = new ListView();      
})(jQuery);

But if I comment out the sentence: _.bindAll(this, 'render');, this will still work. I have searched in google and someone said that the method bindAll() is necessary since if I switched my context, the calling of this.render may unavailable. I feel confused on the "context". and also could some one explain me when the calling (this.render) will unavailable?

回答1:

For the example you've given _.bindAll(this, 'render'); isn't necessary but if you have callback functions where this can possibly be changed to the context of something else, then _bindAll() can be handy.

For instance:

initialize: function(){
  _.bindAll(this, 'render', 'clickFunc');
},
events: {
   'click .someElement': 'clickFunc'
},
clickFunc: function(e) {
   /** If you remove the clickFunc from the list of events in bindAll, 
          'this' will refer to the element that invoked the event.

       Adding the clickFunc event in the _.bindAll, ensures that 'this' stays
          as the view.
   */
  this /** <-- our focal point */
}


回答2:

  • Any methods listed as property values in your view's events hash are automatically bound for you by backbone
  • Any methods in your view that you manually use as event handlers from models or collections should be manually bound via bindAll
    • OR you can provide a context when you register the binding
    • OR you can use EMCA 5's function.bind to get the same result

snippet:

events: {
    'click .win': 'win',
    'click .lose': 'lose'
},
initialize: function () {
    //win and lose are automatically bound for you
    //because they are in the events property

    //refresh must be manually bound
    this.model.on('change', this.refresh);

    //which you can do ECMA5 style if you like
    this.model.on('change', this.refresh.bind(this));

    //OR you can provide a context backbone style
    this.model.on('change:foo', this.fooChange, this);

    //However, since you pretty much never want an unbound function
    //in a view, you can just stick this in all your initialize methods
    //and call it done
    //Note this will bind all functions in your view class if you don't
    //pass specific method names. I recommend this form.
    _.bindAll(this);
},
win: function () {...},
lose: function () {...},
refresh: function () {...},
fooChange: function() {...}

...OOOOORRRR just use CoffeeScript and fat arrows and solve this cleanly at the language level.



回答3:

in this instance you don't need the _.bindAll, but let's say your view have a method that causes a rerender and you do something like this:

..,
myMethod: function() {
    this.$('.someselector').change(this.render);
},

if you don't have _.bindAll for render, your context would be off.



回答4:

Lets take a close look at what _.bindAll does from underscore.js offical docs.

  _.bindAll = function(obj) {
    var i, length = arguments.length, key;
    if (length <= 1) throw new Error('bindAll must be passed function names');
    for (i = 1; i < length; i++) {
      key = arguments[i];
      obj[key] = _.bind(obj[key], obj);
    }
    return obj;
  };

What it does is to automatically bind all its functions to its correct context. (where its function is declared rather than invoked.

I personally think it was a convention for old version of Backbone.js to bind its events, or DOM action listeners. Since new versions Backbone View automatically bind and unbind listeners in events. Find more by search Binding "this" here

I hope it helps.