如何将“this”上下文传递到事件处理程序中?

60

我知道这个问题可能有点不太清晰,但让我稍微澄清一下。

我有一个名为ScrollBanner的类,它大致如下(为了简洁起见省略了很多内容):

function ScrollBanner() {
    this.initialize = function(selector) {
        $('span#banner1-nav').click(this._onClickNavigation);
    }

    this._onClickNavigation = function(event) {
        this.restartTimer(); // this == span#banner1-nav element from this.initialize
        //...
    }

    this.restartTimer() {
        //...
    }
}

正如您所看到的,this.initialize将点击处理程序设置为this._onClickNavigation。有些人可能希望事件处理程序中的this指的是ScrollBanner实例,但不幸的是它并不是。它指的是触发单击事件的元素,在这种情况下是span#banner1-nav

最好的方法是什么,可以使this指向ScrollBanner类实例?

2个回答

103

传统的方式:

this保存到一个变量中:

this.initialize = function(selector) {
    var that = this;
    $('span#banner1-nav').click(function(event) {
       that._onClickNavigation(event);
    });
}

你还可以将this赋值给一个变量,例如instance

function ScrollBanner() {
    var instance = this;
    // ...
}

在所有的调用中,使用instance代替this

总体思路是将this存储在更高作用域的变量中。


ECMAScript5的方法:

ECMAScript5引入了函数的一个新属性:.bind()MDC文档展示了适用于不支持该属性的浏览器的实现方式。通过它,你可以将特定的上下文绑定到一个函数上:

this.initialize = function(selector) {
    $('span#banner1-nav').click(this._onClickNavigation.bind(this));
}

但是在幕后它会做同样的事情。优点是你可以利用浏览器内置的支持功能。

请注意,这与applycall不同。这两者都设置了上下文并且执行函数,而bind仅设置上下文而不执行函数。


jQuery的方式:

jQuery提供了一个方法$.proxy(),也在做同样的事情:

$('span#banner1-nav').click($.proxy(this._onClickNavigation, this));

2
这很有用,但感觉有点不太干净。 :) - josef.van.niekerk
1
jQuery没有一个跨浏览器兼容的bind()函数吗? - josef.van.niekerk
1
@JoeZephyr:是的,我忘了。jQuery有$.proxy:http://api.jquery.com/jQuery.proxy/至少现在你知道所有可能的方法了;) - Felix Kling
@RobG 每个函数都有一个上下文,即“函数上下文”,可以通过使用关键字this来引用。 - ahmehri
@ahmehri——ECMA-262定义了“函数上下文”是什么(http://ecma-international.org/ecma-262/5.1/#sec-10.4)。*this*是函数执行上下文的一个参数,它不是*上下文*本身。 - RobG
显示剩余4条评论

3

我知道这是一个老问题,但我在评论中看到了$.proxy()。是的,它确实改变了对象的上下文,但不适用于jQuery事件。

 $('.selector').click( $.proxy( function() {
     console.log(this); /* this is set to .selector */
 }, this));

$.proxy()会返回在this所指向的作用域中的函数,但是该函数被返回并被click()使用后,作用域会变成.selector元素。

我刚刚测试过了,如果我理解有误,请告诉我。


4
不确定旧版本的jQuery是否有所不同,但是这个例子表明你是错误的:http://jsfiddle.net/mazztgc9/。 - Felix Kling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接