要处理的模式'这'在JavaScript事件处理程序中

Pattern to deal with 'this' in JavaScript event handlers

本文关键字:JavaScript 事件处理 程序 处理 模式      更新时间:2023-09-26

我正试图封装一些代码,以获取并释放Firefox扩展中选项卡的onLoad事件,因此,在必要时,我调用:

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的行为,我很挣扎。我希望能够通过扫描功能访问此浏览器,但无法。

我使用了bind来确保unregisterunload上获得适当的上下文。但是,我无法通过调用scan来完成此操作,因为如果我没有名称,以后将无法删除它。

在JavaScript中做这类事情有一个好的模式吗

我曾尝试将bind(this,this.scan(的结果作为变量存储在构造函数中,但它没有帮助,现在正在努力寻找选项。

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.htmhttp://www.htmlgoodies.com/primers/jsp/article.php/3606701/Javascript-Basics-Part-9.htm

function MyHandler_onLoad()
{
    var self = this;

完成此操作后,self将始终指向处理程序中正确的对象。

解决方案:不要使用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;
}

甚至更好?向上移动全局依赖项,无法访问选项卡和浏览器属性(即使其"私有"(

您甚至可以选择隐藏register和unregister函数,因为我不确定您是否需要它们,因为它似乎已经附加了自己。

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