Ответ 1
Несколько вещей:
-
Большинство людей будут предлагать что-то вроде
var self = this
, потому что это быстро и просто. -
Но
var self = this
не отделяет объект вида полностью от логики представления, которая исходит из более формального фона С# и смотрит на ваш код, звучит как что-то, что вы хотите сделать. -
Чтобы выполнить обратный вызов только при возникновении события, оберните обработчик в функцию, чтобы он сразу оценил, но выполнялся только тогда, когда и если происходит событие
keydown
(см. код ниже). -
Понимание области действия в JS: каков бы ни был контекст выполнения, также является текущей областью. Ваш слушатель был добавлен в метод (называемый
listen
) наKeyboard.prototype
, но событиеkeydown
фактически запущено наwindow
- обработчик выполняется в другом контексте, чем там, где он был определен; он выполняется в контексте того, что вызывает его, в этом случаеwindow
, поэтому он привязан кwindow
, если вы не привяжете его к другому объекту черезbind
илиapply
, когда он определен.
В вашем коде window
- это вид, с которым взаимодействует пользователь, а Keyboard
- это контроллер представления. В шаблонах MVC, как то, к чему вы, вероятно, привыкли в С#/. NET, представления не говорят себе, что делать, когда что-то происходит, диспетчеры рассказывают мнения о том, что делать. Итак, если вы должны назначить ссылку на контроллер, используя var self = this
, как это делают многие, представление будет управлять собой, но только для этого конкретного обработчика событий keydown
. Это непоследовательно и будет трудно справиться в крупном проекте.
Решение:
Keyboard.prototype.listen = function() {
window.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
}
Лучшее решение:
Keyboard.prototype.view = window;
Keyboard.prototype.listen = function() {
this.view.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
}
Лучшее решение (пока ES6 class
не будет готов):
// define
function addViewController(view) {
function ViewController() {
this.handle_keydown = function(args) {
// handle keydown events
};
this.listen = function() {
this.view.addEventListener('keydown', function(e) {
this.handle_keydown(e);
}.bind(this), false);
};
this.view = view;
return this;
}
return new ViewController(view);
}
// implement
var keyboard = addViewController(window);
keyboard.listen();
- Примечание:
.bind()
совместим с ECMAScript 5+; если вам нужно решение для старых браузеров, Mozilla опубликовала отличную альтернативу.bind()
с помощьюfunctions
и.call()
:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Изменить: Здесь будет создан ваш экземпляр объекта Keyboard
с использованием этого нового модульного решения: