Pull to refresh

Классовый мутатор Binds.

Reading time3 min
Views1.6K
Original author: Jan Kassens
В обсуждении недавнего топика хабрасообщество заинтересовалось подробностями написания классов для MooTools и, в частности, мутаторами. В связи с этим мне захотелось что-нибудь написать на эту тему, пока не наткнулся на статью одного из разработчиков MooTools. В этом топике привожу перевод статьи, в которой Jan Kassens описывает пример использования классовых мутаторов.

Во время написания класса вам может понадобиться привязать метод класса к событию в качастве обработчика и использовать this внутри него в качестве экземпляра класса. Вы можете сказать, что это не проблема при использовании bind(). Все это верно, но ровно до тех пор, пока дело не доходит до удаления обработчика события, т.к. Function::bind() работает так, что возвращает новую функцию, оборачивающую оригинал. Поэтому Вам нужно где-то сохранить ту самую обертку, чтобы удалить обработчик (без удаления всех обработчиков событий элемента, что не очень хорошо внутри переносимого класса).

Примечание автора перевода. Автор статьи имеет в виду случай, когда обработчик события назначается с помощью el.addEvent('click', myFn.bind(this)). Таким образом его нельзя удалить с помощью el.removeEvent('click', myFn.bind(this)), потому что bind() вернет уже новую функцию, не ту что была использована в addEvent(). Единственным в данном случае решением будет удаление всех обработчиков элемента с помощью el.removeEvents('click'), но это затронет все обработчики, включая те, которые могли быть назначены сторонними классами.

Что я видел несколько раз — это объект, содержащий все привязанные функции, который создается в конструкторе, как видно из примера:
var MyClass = new Class({
  initialize: function(){
   this.bound = {
     sayHello: this.sayHello.bind(this),
     sayGoodbye: this.sayGoodbye.bind(this)
   }
   // Далее используем только this.bound.sayHello и
   // this.bound.sayGoodbye внутри класса
  },

  sayHello: function() { /* ... */ },
  sayGoodbye: function() { /* ... */ }
});

Мне такое решение не понравилось, потому что оно слишком громоздко: зачем мне использовать this.bound.myFn всегда, когда я пользуюсь привязанными функциями? И, потом, я не хочу каждый раз привязывать эти функции вручную. После рассмотрения различных решений я пришел к одному, оптимальному по скорости (не бойтесь, это быстрее, чем решение выше) и удобству.

Это — новый, так называемый «классовый мутатор» Binds. Многие из вас, возможно, не слышали о классовых мутаторах раньше, но точно их использовали при написании своих классов. Встроенные мутаторы: Implements и Extends, а вот и код Binds:
Class.Mutators.Binds = function(self, methods) {
  $splat(methods).each(function(method){
   var fn = self[method];
   self[method] = function(){
     return fn.apply(self, arguments);
   };
  });
};

Этот мутатор переопределяет все методы, переданные в него в строках новыми версиями, привязанными к экземпляру. Binds: 'foo' просто привяжет foo к классу, Binds: ['foo', 'bar'] привяжет foo и bar. Довольно просто, не правда ли?

Теперь давайте посмотрим, насколько упростится класс с использованием мутатора Binds:
var MyClass = new Class({
  Binds: ['sayHello', 'sayGoodbye'],

  initialize: function(){
   // Теперь используем только this.sayHello и
   // this.sayGoodbye внутри класса
  },

  sayHello: function() { /* ... */ },
  sayGoodbye: function() { /* ... */ }
});

Надеюсь, вы немного разобрались и сможете найти этому применение.
Tags:
Hubs:
+18
Comments11

Articles

Change theme settings