В обсуждении недавнего топика хабрасообщество заинтересовалось подробностями написания классов для 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() { /* ... */ }
});
Надеюсь, вы немного разобрались и сможете найти этому применение.