Подтвердить что ты не робот

Область Javascript addEventListener и это

Я разработчик С#, экспериментирующий с JavaScript, и я пытаюсь разглядеть область видимости:)

У меня есть следующий код, который содержит addEventListener, в котором я хочу использовать поле из моего объекта:

(function(window) {

    function Keyboard() {
        this.keys = {};
    }

    Keyboard.prototype.handle_keydown = function(args) {
        this.keys[args.keyCode] = true;
    }

    Keyboard.prototype.listen = function() {
        window.addEventListener('keydown', this.handle_keydown);
    }

    app.util.keyboard = new Keyboard();

})(window);

Я хотел бы использовать массив ключей в моем hander, но понимаю, что я не могу получить доступ, используя это, потому что это окно в этом контексте (правильно?). Если я изменю его на

app.util.keyboard.keys[args.keyCode] = true;

он работает, но я не уверен, что это хороший способ его исправить.

Я нашел этот вопрос, который кажется довольно похожим, но я не уверен, как я могу поместить его в свой пример.

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

4b9b3361

Ответ 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 с использованием этого нового модульного решения: enter image description here

Ответ 2

Keyboard.prototype.listen = function() {
    var self = this;
    window.addEventListener('keydown', function(event) {
       self.handle_keydown(event);
       // self is your Keyboard object. You can refer to all your properties from this
    });
}

Как работает этот код:

  • Мы создаем переменную self, в которой хранится ссылка на переменную this.
  • Внутренняя функция - это замыкание, поэтому она имеет ссылку на self.
  • Когда функция закрытия называется: this указывает на объект dom, а self указывает на объект клавиатуры.
  • Закрытие вызывается с помощью event в качестве параметра, который мы передаем функции-члену объекта клавиатуры.

Ответ 3

Как насчет

function Keyboard() {
    this.keys = {};
    var self = this;
    this.handle_keydown = function(args) {
        self.keys[args.keyCode] = true;
    }
    this.listen = function() {
        window.addEventListener('keydown', this.handle_keydown);
    }
}
app.util.keyboard = new Keyboard();