如何从事件处理程序中引用对象实例

3
在下面的代码中,除了将对象实例作为全局变量引入外,是否有更好的方法从handleClick()中引用它?
var Widget = function() {
  this.property = 'value';
  this.bindEvents();
}

Widget.prototype = {

  bindEvents: function() {
    $('button').on('click', this.handleClick);
  },

  handleClick: function() {
    var self = window.Widget;

    console.log(self.property);
  }
}

window.Widget = new Widget();

这个问题是在询问同样的事情,而(未被接受的)答案是将回调传递给$.on()并从那里调用处理程序,如下所示,传入实例作为参数:

bindEvents: function() {
  var self = this;

  $('button').on('click', function() {
    self.handleClick.apply(self);
  });
}

这种通过将实例传递的技术是否真的是正确的方式,除了我展示的两种方法外,还有其他更好的方式吗?


1
看看这些问题:http://stackoverflow.com/q/18210083/218196,https://dev59.com/B2025IYBdhLWcg3wnXWf,http://stackoverflow.com/q/737454/218196,https://dev59.com/-HRB5IYBdhLWcg3wxZ1K。 - Felix Kling
感谢提供重复链接 - 如果我知道要搜索$.proxy,可能就不会发布我的问题了。但我还是会保留它,除非有反对意见 - 因为有一些很好的答案,并且可能帮助某人查看代码中引用的多种技术。 - cantera
顺便说一句,这是我使用的搜索链接:http://stackoverflow.com/search?q=%5Bjquery%5D+oop+event+handler+context - Felix Kling
5个回答

5

对象可以作为 eventData 参数传递给 on(),如下所示:

var Widget = function () {
    this.property = 'value';
    this.bindEvents();
}

Widget.prototype = {

    bindEvents: function () {
        $('button').on('click', {o: this}, this.handleClick);
    },

    handleClick: function (e) {
        var widgt = e.data.o;
        console.log(widgt.property);
    }
}

window.Widget = new Widget();

FIDDLE

这样可以保持事件处理程序的作用域。


非常有趣的方法。让我意识到在回调函数中调用处理程序具有不必传递事件对象的优点。 - cantera
@cantera25 - 的确,this仍然是事件处理程序中的点击按钮,而不是Widget对象。 - adeneo
这种方法的另一个优点是,您可以轻松地使用 $('button').off('click', this.handleClick); 取消绑定事件监听器。 - rassoh

1
你可以使用 bind()
bindEvents: function() {
  $('button').on('click', function() {
    this.handleClick();
  }.bind(this)); 
}

但是,当涉及到IE时,只有在IE >= 9中才能工作。

编辑:在旧版IE中,您可以使用@Kevin B在评论中建议的jQuery的{{link1: $.proxy()}}:

bindEvents: function() {
  $('button').on('click', $.proxy(function() {
    this.handleClick();
  }, this)); 
}

在IE中,您可以使用jQuery的版本.bind$.proxy() - Kevin B
@kamituel - 谢谢,使用.bind()与我在问题中展示的第二种方法相比有什么优势吗? - cantera
@cantera25 - 我已经在答案中使用了$.proxy。 - kamituel
1
@FelixKling - bind() 会不会稍微快一点?(不需要到外部作用域) - kamituel
1
我来回答自己:这个SO答案解释了为什么bind()倾向于更慢。 - kamituel
显示剩余3条评论

0

保留this的最佳方式是lambda函数

$('button').on('click', () => this.handleClick());

或者如果您想保留对事件的引用:

$('button').on('click', (event) => this.handleClick(event));

Lambda函数的特殊之处在于,您不需要在(可能不同的)上下文中定义另一个函数。Lambda术语只是一条指令,因此它是定义它的对象的一部分 - 在您的情况下,这个对象是通过window.Widget = new Widget()创建的实例。

0
如@kamituel所说,可以使用`bind`函数:
Widget.prototype = {
  bindEvents: function() {
    $('button').on('click', this.handleClick.bind(this));
  },
  handleClick: function() {
    console.log(this.property);
  }
}

0

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