Пользователи Backbone.js часто используют методы Bind и BindAll, предоставляемые им библиотекой Underscore.js. В этом блоге я собираюсь обсудить, зачем нужны эти методы и как они работают.
Все начинается с подачи заявки
ФункцияbindAll использует внутреннюю привязку.Аbind, в свою очередь, использует apply. Поэтому важно понимать, что делает apply.
Если я выполню приведенный выше код, я получу «[окно объекта] красиво».var func = function beautiful(){ alert(this + ' is beautiful'); }; func();
Я получаю это сообщение, потому что при вызове функции она равна окну, глобальному объекту по умолчанию.
Чтобы изменить это значение, мы можем использовать метод Apply, как показано ниже.
var func = function beautiful(){
alert(this + ' is beautiful');
};
func.apply('Internet');
В приведенном выше случае будет отображаться сообщение «Интернет – это красиво».
Аналогично, следующий код выдаст «Пляж прекрасен».
var func = function beautiful(){
alert(this + ' is beautiful');
};
func.apply('Beach'); //Beach is beautiful
Короче говоря, apply позволяет нам контролировать значение this при вызове функции.
Зачем нужна привязка?
Чтобы понять, зачем нужен метод привязки, сначала давайте рассмотрим следующий пример.
function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says(); //Ruby rocks!
Приведенный выше пример довольно прост. Объект john является экземпляром Developer, и при вызове функцииsay мы получим правильное уведомление.
Обратите внимание, что когда мы вызываемsays, мы вызываем его следующим образом: john.says().
Если мы просто хотим освоить функцию, которая возвращает результат, нам нужно запустить john.says. Таким образом, приведенный выше код можно сломать с помощью следующего обзора.
function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();// undefined rocks!
Код выше аналогичен приведенному выше коду.
Все, что мы сделали, это сохранили функцию в переменной с именем func. Если мы вызовем эту функцию, то должны получить ожидаемое сообщение.
Однако, если мы запустим этот код, предупреждающее сообщение будет «неопределенные камни!» Мы получаем «неопределенные камни!» потому что в этом случае func вызывалась в глобальном контексте.
Когда функция выполняется, это указывает на глобальный объект с именем window. А у объекта окна нет свойства с именем навык.
Таким образом, выходное значение this.skill не определено.
Ранее мы видели, что с помощью apply мы можем решить вызванную этим проблему.
Итак, давайте попробуем использовать apply. function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func.apply(john);
Код выше решает нашу проблему.
На этот раз мы получили предупреждающее сообщение: «Рубин рулит!» Однако есть проблема и большая.
В мире JavaScript функции являются объектами первого класса.
Причина, по которой мы создаем функцию, заключается в том, что мы можем легко ее передавать.
В приведенном выше случае мы создали функцию под названием func. Однако теперь вместе с функцией func нам нужно везде передавать переменную john. Это не очень хорошая идея.
Во-вторых, ответственность за правильный вызов этой функции была перенесена с функции-создателя на функцию-потребитель.
Это не очень хороший API. Мы должны попытаться создать функции, которые могут быть легко вызваны их потребителями.
И здесь в игру вступает привязка.
Как связывание решает проблему
Во-первых, давайте посмотрим, как использование привязки решает проблему.
function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = _.bind(john.says, john);
func();// Ruby rocks!
Чтобы решить эту проблему, нам нужна функция, которая уже сопоставлена с john, чтобы нам не приходилось беспокоиться о ней повсюду.
Именно это и делает метод привязки.
Он возвращает новую функцию, и ее значение становится тем, которое мы предоставили.
Вот фрагмент кода метода привязки: return function() {
return func.apply(obj, args.concat(slice.call(arguments)));
};
Как вы можете видеть внутри, использование привязки применяется для установки этого параметра в качестве второго параметра, который мы передаем при вызове привязки.
Обратите внимание, что привязка не изменяет существующую функцию.
Он возвращает новую функцию, и вам нужно ее использовать.
Как BindAll решает проблему
Вместо связывания мы также можем использовать связываниеAll. Вот решение с помощью BindAll. function Developer(skill) {
this.skill = skill;
this.says = function(){
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
_.bindAll(john, 'says');
var func = john.says;
func(); //Ruby rocks!
Приведенный выше код похож на решение для привязки, но есть несколько существенных отличий.
Первое отличие состоит в том, что нам не нужно беспокоиться о возвращаемом значении методаbindAll. В случае привязки мы должны использовать функцию возврата.
В BindAll мы не беспокоимся о возвращаемом значении, но за это приходится платить.
Фактически,bindAll изменяет функцию.
Что это значит? Вы можете видеть, что у объекта john есть свойствоsays, которое возвращает функцию.
Метод bindAll изменяет свойствоsays так, что когда функция возвращает функцию, она уже привязана к объекту john.
Вот фрагмент кода метода BindAll: function(f) { obj[f] = _.bind(obj[f], obj); }
Обратите внимание, что метод bindAll внутренне вызывает метод привязки и заменяет значение существующего свойства функцией, возвращенной привязкой.
Еще одно различие между связыванием и связыванием Все заключается в том, что в связывании первым параметром является функция john.says, а вторым — объект john. В методеbindAll первым параметром является объект john, а вторым параметром является не функция, а имя свойства.
На что нужно обратить внимание
При разработке приложений Backbone.js кто-то написал такой код: window.ProductView = Backbone.View.extend({
initialize: function() {
_.bind(this.render, this);
this.model.bind('change', this.render);
}
});
Приведенный выше код не будет работать, поскольку возвращаемое значение привязки не используется.
Правильное использование будет: window.ProductView = Backbone.View.extend({
initialize: function() {
this.model.bind('change', _.bind(this.render, this));
}
});
Или вы можете использовать bindAll, как показано ниже: window.ProductView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, this.render);
this.model.bind('change', this.render);
}
});
Теги: #JavaScript #backbone.js #Разработка веб-сайтов #JavaScript
-
Два В Одном
19 Oct, 24 -
Репортаж С Пресс-Конференции В. Селезнева
19 Oct, 24 -
Разница Между Разметкой И Представлением
19 Oct, 24 -
Традиционное Тестирование Скоро Умрет
19 Oct, 24