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

时间:2011-04-24 18:55:14

标签: javascript this

我正在尝试封装一些代码以获取和释放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的行为,我正在努力。我希望能够从我的扫描功能访问this.browser,但不能。

我已使用bind确保unregister获得unload上的相应上下文。但是,我无法通过调用scan来执行此操作,因为如果我没有名字,我将无法将其删除。

在JavaScript中执行此类操作是否有良好的模式?

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

3 个答案:

答案 0 :(得分:3)

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 :(得分:1)

function MyHandler_onLoad()
{
    var self = this;

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

答案 2 :(得分:0)

解决方案:请勿使用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