Как использовать ключевое слово this в обёртке мыши в правильном контексте в Javascript? - PullRequest
1 голос
/ 22 апреля 2010

Я пытаюсь написать простую оболочку для поведения мыши. Это мой текущий код:

function MouseWrapper() {

  this.mouseDown = 0;  
  this.OnMouseDownEvent = null;
  this.OnMouseUpEvent = null;
  document.body.onmousedown = this.OnMouseDown;  
  document.body.onmouseup = this.OnMouseUp;
}

MouseWrapper.prototype.Subscribe = function (eventName, fn) {

  // Subscribe a function to the event
  if (eventName == 'MouseDown') {
    this.OnMouseDownEvent = fn;
  } else if (eventName == 'MouseUp') {
    this.OnMouseUpEvent = fn;
  } else {    
    alert('Subscribe: Unknown event.'); 
  }  
}  


MouseWrapper.prototype.OnMouseDown = function () {  
  this.mouseDown = 1;  
  // Fire event
  $.dump(this.OnMouseDownEvent);
  if (this.OnMouseDownEvent != null) {
    alert('test');
    this.OnMouseDownEvent();
  }
}

MouseWrapper.prototype.OnMouseUp = function () {

  this.mouseDown = 0;
  // Fire event
  if (this.OnMouseUpEvent != null) {
    this.OnMouseUpEvent();
  }  
}

Из того, что я понял, кажется, что в MouseWrapper.prototype.OnMouseUp и MouseWrapper.prototype.OnMouseDown ключевое слово "this" означает не текущий экземпляр MouseWrapper, а что-то еще. И имеет смысл, что это не указывает на мой пример, но как решить проблему?

Я хочу решить проблему правильно, я не хочу использовать что-то грязное.

Мое мышление: * используйте шаблон синглтона (мышь всего одна) * передать как-то мой экземпляр OnMouseDown / Up - как?

Спасибо за помощь!

Ответы [ 2 ]

3 голосов
/ 22 апреля 2010

Приведенное выше решение хорошо, но более пригодный для повторного использования способ состоит в том, чтобы «привязать» ваш метод к контексту, создав метод, который создает это закрытие для вас. Например

Function.bind = function(method, context) {
  return function() {
    return method.apply(context, arguments);
  }
}

Следуя примеру Слакса, вы получите:

document.body.onmousedown = Function.bind(this.OnMouseDown,this);
document.body.onmouseup = Function.bind(this.OnMouseUp, this); 

или вы можете сделать это для Function.prototype для синтаксического сахара.

Function.prototype.bind = function(context) {
  return function() {
    // since this is a prototype method, "this" is the method to be called
    return this.apply(context, arguments);
  }
}

document.body.onmousedown = this.OnMouseDown.bind(this);
document.body.onmouseup = this.OnMouseUp.bind(this); 

Вы также можете связать аргументы для вызова, а также контекст ... спросить, если вы заинтересованы.

Синглтонный подход, хотя он и работает, является взломом. Это добавляет глобальные перемены вместо правильного решения проблем. Это означает, что если вам нужно поведение в двух местах, оно не будет работать.

2 голосов
/ 22 апреля 2010

В Javascript, в отличие от большинства языков, значение ключевого слова this определяется при вызове функции.

Например:

var dumper = function() { alert(this); };
var str1 = "A";
str1.dump = dumper;
str1.dump();        //Alerts A

var str2 = "B";
str2.dump = str1.dump;
str2.dump();        //Alerts B

Когда браузер вызывает ваш обработчик событий, он вызывает его в контексте элемента DOM, поэтому this не то, что вы думаете.

Чтобы обойти это, вам нужно использовать анонимный метод, который вызывает ваши обработчики в правильном контексте.

Например:

var self = this;

document.body.onmousedown = function(e) { return self.OnMouseDown(e); };
document.body.onmouseup = function(e) { return self.OnMouseUp(e); };

Кроме того, вы не должны обрабатывать подобные события.

Вместо этого звоните attachEvent / addEventListener.

...