如何在事件处理程序中访问 `this`?

4
我是一名有用的助手,可以进行文本翻译。
我有一个类,创建了一个DOM元素,并需要捕获所有点击事件。
简化代码:
function myClass()
{
  this.domElement = document.createElement("canvas");
  this.domElement.addEventListener("click", this.handleClick);
}
myClass.prototype.handleClick = function(evt)
{
  alert("Clicked!");
  // How to modify `this` object?
}

现在我想要在handleClick()函数中修改myClass实例的某些属性和变量。但是this指向的当然是画布对象。

问题:如何在事件处理程序中访问对象的this

3个回答

3
通过封闭对实例的引用并使用apply来强制函数作用域,可以实现这一点:
第1步中,我展示了您的示例,显示this是被单击的元素:http://jsfiddle.net/JAAulde/GJXpQ/ 在第2步中,我有一个示例,在您的构造函数中存储了对实例的引用,然后将匿名函数设置为单击处理程序,并从存储的引用调用您的单击方法。http://jsfiddle.net/JAAulde/GJXpQ/1/如果您不需要访问被单击的元素,则会导致您的单击处理程序内的this成为实例,并且将适用于您。
在第3步中,我存储了相同的引用,并使用了匿名函数,但在该函数内部,我获取传入单击的anon函数的参数,将实例的引用添加到这些参数中,并在单击元素的作用域内调用单击处理程序并传递新的参数集。http://jsfiddle.net/JAAulde/GJXpQ/2/使用这种方法,在单击处理程序内,我可以通过this访问单击的元素,并通过instance访问myClass的实例。
希望这有所帮助。这可能会令人困惑,请提问如果需要。

非常感谢您提供的三种解决方案!我最喜欢的是第二个方案(既好又简单)。但是我为什么需要访问原始的 this?当我想要访问 DOM 元素时,我通过 evt.target 来完成。 - ComFreek
这只是个人偏好和代码编写方式的问题。如果你喜欢2并使用evt.target,那是合理的。但如果你正在适应一些现有的代码,你可能会遇到需要不同作用域的情况,所以在那种情况下3可能更好用。 - JAAulde
好的,谢谢。我正在编写自己的框架,所以在这方面没有任何问题。答案已被接受 ;) - ComFreek

2
你可以像这样做:
function myClass() {
  var self = this;

  this.domElement = document.createElement("canvas");
  this.domElement.addEventListener("click", function(evt){
      // use self here
  });
}

由于监听器实际上是闭包,它会保留对变量self的引用,该变量是您正在观察的对象。实际上,this引用画布元素,正如您所发现的。

另一种方法可以工作,并保持方法分离:

function myClass(){
  var self = this;

  this.domElement = document.createElement("canvas");
  this.domElement.addEventListener("click", function(evt){
    myClass.prototype.call(self, evt);
  });
}
myClass.prototype.handleClick = function(evt){
  alert("Clicked!");
  // How to modify `this` object?
}

现在这个使用Function.call的示例将this引用分配给了特定的对象。

谢谢!我已经更新了示例以测试对'this'的访问:http://jsfiddle.net/StWu9/. - ComFreek

1

您可以使用.bind,它可以“冻结”this值并预设一个值:http://jsfiddle.net/TKAHg/

.bind返回一个新函数,该函数与原始函数执行相同的操作,但它设置了this,以便您可以依赖于提供的值。

虽然旧版浏览器不支持.bind,但是MDC为其提供了一个shim

// bind 'this' value inside handleClick when clicked
this.domElement.addEventListener("click", this.handleClick.bind(this));

谢谢!我已经更新了示例,所以该元素可以被点击:http://jsfiddle.net/TKAHg/1/。 旧浏览器不是问题,因为我使用了canvas元素。但我需要支持Opeara和Safari。 - ComFreek

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