jQuery эквивалент MooTools bind(this)

#javascript #jquery #mootools #mootools-events

#javascript #jquery #mootools #mootools-события

Вопрос:

Я пытаюсь переписать класс всплывающих подсказок Mootools в jQuery, используя этот плагин класса. Когда создается экземпляр моего класса, я подключаю прослушиватель событий к целевой ссылке, которая приведет к исчезновению всплывающей подсказки.

При обратных вызовах событий jQuery присваивает ключевое слово «this» целевому объекту события, поэтому, чтобы сохранить ссылку на свойства класса, который я использую apply() , чтобы «this» означало экземпляр класса. По-видимому, это аналог в jQuery удобной bind() функции Mootools от Mootools.

К сожалению, когда я использую apply() , я теряю параметр события обратного вызова. Например, в этом бите я получаю ошибку «e не определено» во второй строке.

 this.target.bind('click', function(e){
    e.preventDefault();
    var tip = this.opts.tip;
    tip.fadeOut(500, function(){
        tip.bind('click', function(){
            showing = false;
        })
    });
}.apply(this))
  

Я упускаю какой-то трюк здесь? Кто-нибудь знает способ обойти эту проблему?

Ответ №1:

TBH, mootools .bind как вы это называете, есть только Function.bind в ES5 — и доступен изначально в браузерах, которые поддерживают спецификацию js 1.8.5 . MooTools просто улучшает браузеры, в которых его еще нет, но позволяет сохранить собственную реализацию в прототипе — если таковой имеется.

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Вы можете легко реализовать это как Function.prototype.bind декоратор, если он недоступен изначально, и использовать его, как указано в примере выше:

 // Function.prototype.bind polyfill
if ( !Function.prototype.bind ) {

  Function.prototype.bind = function( obj ) {
    if(typeof this !== 'function') // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');

    var slice = [].slice,
        args = slice.call(arguments, 1), 
        self = this, 
        nop = function () {}, 
        bound = function () {
          return self.apply( this instanceof nop ? this : ( obj || {} ), 
                              args.concat( slice.call(arguments) ) );    
        };

    bound.prototype = this.prototype;

    return bound;
  };
}
  

Как вы можете видеть, это немного сложнее, чем простой .apply / .call

Следует учитывать одну вещь: нужно ли вам использовать bind или вместо этого вы можете сохранить ссылку.

например.

 var self = this;
this.target.bind("click", function(e) {
    var tip = self.opts.tip;
});
  

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

 this.element.addEvents({
    click: this.showTip.bind(this),
    mouseleave: this.hideTip.bind(this)
});
  

В этом случае сохранение ссылки не сработает, хотя вы можете переписать ее как

 var self = this;
this.element.addEvents({
    click: function(e) {
        self.showTip(e);
    }
});
  

Конкретная реализация jQuery является proxy http://api.jquery.com/jquery.proxy

Комментарии:

1. Димитар, ты ходячая энциклопедия JS! Спасибо за подробное объяснение. В этой ситуации ваше предложение ссылки кажется наилучшим, поэтому я бы сделал так: ` var self = this; this.target.bind(‘click’, function(e){ e.preventDefault(); self.toggleTip(); })` в моем методе инициализации, где toggleTip() — это отдельный обратный вызов click. Отличный совет, спасибо!

2. @Dimitar: Действительно отлично работает. спасибо. (at)в целом: обратите внимание, что этот метод функционального программирования называется каррированием ( dustindiaz.com/javascript-curry ). jQuery имеет аналогичное расширение прототипа имени метода ‘bind’, которое может несколько сбивать с толку, поскольку оно используется для обработки событий и объявлено в нефункциях. В jQuery также используется context в $.ajax для аналогичной цели.

Ответ №2:

Все события, которые выполняются для некоторого элемента (например, ‘click’ является одним из них), должны иметь целевое свойство, указывающее на этот элемент

 var $this = $(e.target); // $this will be the clicked element
  

JSFiddle

Комментарии:

1. Спасибо mkilmanas — это свойство, которое я надеялся использовать. К сожалению, когда я добавил apply () в конец моей функции, я потерял к ней доступ.