Когда мне нужно использовать _.bindAll() в Backbone.js?
Я изучаю backbone.js и чувствую смущение этим:
Я следую руководству:
http://arturadib.com/hello-backbonejs/
как вы можете видеть в первом примере (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);
Но если я прокомментирую предложение: _.bindAll(this, 'render');
, это все равно будет работать. Я искал в google, и кто-то сказал, что метод bindAll()
необходим, так как если бы я переключил свой контекст, вызов this.render
может быть недоступен. Я чувствую смущение от "контекста". а также может ли кто-нибудь объяснить мне, когда вызов (this.render
) будет недоступен?
Ответы
Ответ 1
Для примера, который вы указали _.bindAll(this, 'render');
, не обязательно, но если у вас есть функции обратного вызова, где this
можно изменить в контексте чего-то другого, тогда _bindAll()
может быть удобно.
Например:
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
- Любые методы, перечисленные как значения свойств в вашем представлении, хеш событий автоматически привязаны к вам по магистрали
- Любые методы, которые вы используете вручную как обработчики событий из моделей или коллекций, должны быть связаны вручную через
bindAll
- ИЛИ вы можете предоставить контекст при регистрации привязки
- ИЛИ вы можете использовать EMCA 5 function.bind, чтобы получить тот же результат
сниппет:
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 просто используйте CoffeeScript и жирные стрелки и решите это на уровне языка.
Ответ 3
в этом случае вам не нужен _.bindAll
, но пусть у вашего представления есть метод, который вызывает повтор, и вы делаете что-то вроде этого:
..,
myMethod: function() {
this.$('.someselector').change(this.render);
},
если у вас нет _.bindAll
для render
, ваш контекст будет отключен.
Ответ 4
Давайте внимательно рассмотрим, что _.bindAll
делает из underscore.js оффициальные документы.
_.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;
};
Что он делает, так это автоматически привязывать все свои функции к правильному контексту. (где его функция объявлена, а не вызывается.
Я лично считаю, что для старой версии Backbone.js это было соглашение, чтобы связать своих слушателей действий events
или DOM. Поскольку новые версии Backbone View
автоматически связывают и отвязывают прослушиватели в events
. Найти больше по запросу Binding "this"
здесь
Надеюсь, это поможет.