Шаблон для работы с этим в обработчиках событий JavaScript - PullRequest
0 голосов
/ 24 апреля 2011

Я пытаюсь инкапсулировать некоторый код для захвата и выпуска события onLoad для вкладки в расширении Firefox, чтобы при необходимости я вызывал:

var onLoad = new MyHandler_onLoad();

И затем, когда я закончил,Я звоню:

onLoad.unregister();

В принципе, этот код реализует вышеупомянутый штраф, пока вы не углубитесь в более грубые детали.

function bind(scope, fn) {
    return function(){
    fn.apply(scope, arguments);
};

function MyHandler_onLoad()
{
    this.scan = function() {
        do_scan(this.browser); // this.browser == undefined
    };

    this.register = function() {
        this.tab.addEventListener("load", this.scan, false);
    };

    this.unregister = function() {
        this.tab.removeEventListener("load", this.scan, false);
    };  

    this.tab = gBrowser.selectedTab;
    this.browser = gBrowser.selectedBrowser;
    this.register();
    window.addEventListener("unload", bind(this, this.unregister), false);
};

Из-за поведения JavaScript this, яборюсь.Я хочу получить доступ к this.browser из функции сканирования, но не могу.

Я использовал bind, чтобы unregister получил соответствующий контекст на unload.Но я не могу сделать это с помощью вызова scan, так как я не смогу удалить его позже, если у меня нет имени.

Есть ли хороший шаблон дляделать что-то подобное в JavaScript?

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

Ответы [ 3 ]

3 голосов
/ 24 апреля 2011

this в JavaScript всегда указывает на текущий объект .Если текущего объекта нет, this указывает на window, что составляет всегда область верхнего уровня (в любом случае в браузере)

Например:

function(){
   ...
   this.foo = function(){
      this;
      // There is no object here, so `this` points to `window`
   }
}

function foo(){
    this;
    // again, no object so `this` points to window`
}
foo();

function foo(){
    this;
    // because initialized with `new`, `this` points to an instance of `foo`
    this.bar = function(){
       this;
       // no object, `this` points to `window`
    }
}
var foobar = new foo();
// above is roughly equivalent to: foo.apply({}, arguments);  Note the new object

foobar.bar();

var foo = {
   bar : function(){
      this;
      // `this` points at `foo` -- note the object literal
   }
};

function foo(){
}
foo.prototype.bar = function(){
    this;
    // `this` points to the instance of `foo`
}
var foobar = new foo();
foobar.bar();

Концепция привязки позволяет блокировать переменную thisк тому, что вы хотите, так как последний вызов функции осуществляется через .apply(scope, params), поэтому, возвращаясь к вашему первоначальному вопросу, мой последний приведенный выше пример будет работать, так будет:

function foo(){
    this.scan = bind(this, function(){
       this;
       // `this` points to instance of `foo` IF `foo` is instantiated
       // with `new` keyword.
    });
}
new foo()

Если вы хотите понятькроме того, у меня есть две статьи, которые я написал давным-давно, которые должны помочь:

http://www.htmlgoodies.com/primers/jsp/article.php/3600451/Javascript-Basics-Part-8.htm http://www.htmlgoodies.com/primers/jsp/article.php/3606701/Javascript-Basics-Part-9.htm

1 голос
/ 24 апреля 2011
function MyHandler_onLoad()
{
    var self = this;

Сделав это, self всегда будет указывать на правильный объект в ваших обработчиках.

0 голосов
/ 24 апреля 2011

Решение: не используйте this.

Вот альтернативный способ определения MyHandler_onLoad

function MyHandler_onLoad() {
    var onload_handler = {
        scan: function() {
            do_scan(onload_handler.browser); // onload_handler.browser == undefined
        },
        register = function() {
            onload_handler.tab.addEventListener("load", onload_handler.scan, false);
        },
        unregister = function() {
            onload_handler.tab.removeEventListener("load", onload_handler.scan, false);
        }
    };
    onload_handler.tab = gBrowser.selectedTab;
    onload_handler.browser = gBrowser.selectedBrowser;
    onload_handler.register();
    window.addEventListener("unload", bind(onload_handler, onload_handler.unregister), false);
    return onload_handler;
}

Еще лучше? Переместить глобальные зависимости вверх и не иметь доступа к вкладкам и свойствам браузера (т.е. сделать их «приватными»)

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

var handler = MyHandler_onLoad(gBrowser.selectedTab, gBrowser.selectedBrowser);

function MyHandler_onLoad(tab, browser) {
    var onload_handler = {
        scan: function() {
            do_scan(browser); // browser == undefined
        },
        register = function() {
            tab.addEventListener("load", onload_handler.scan, false);
        },
        unregister = function() {
            tab.removeEventListener("load", onload_handler.scan, false);
        }
    };
    onload_handler.register();
    window.addEventListener("unload", bind(onload_handler, onload_handler.unregister), false);
    return onload_handler;
}

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

О, и вам не нужно использовать new.

...