Понимание Связывания И Связыванияall В Backbone.js

Пользователи 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

Вместе с данным постом часто просматривают: