如何有效地将DOM事件注册到特定的JavaScript对象实例

How to efficiently register a DOM event with a specific JavaScript object instance

本文关键字:JavaScript 实例 对象 注册 有效地 DOM 事件      更新时间:2023-09-26

在我的web应用程序中,我有一个自定义对象,我用对象函数构造器定义了它,并通过构造器原型应用了各种共享属性。

MyObject = function (Name) {
  this.Name = Name;
  this.ListItem1 = document.createElement('li');
  this.ListItem1.onclick = this.SetActive;
  this.ListItem2 = document.createElement('li');
  this.ListItem2.onclick = this.SetActive;
}
MyObject.prototype.SetActive = function () {
  alert('SetActive: ' + this.Name);
}

现在这是一个简化的例子,我的实际对象有更多的DOM元素附加到它,每个DOM元素都有许多不同的事件侦听器。我的对象也有很多其他的属性和方法。我也可能有这个对象的数千个实例,所以代码效率很重要。

我现在的问题是,当一个DOM事件被触发时,事件处理程序的'this'属性被设置为实际的DOM元素,而不是我的对象实例。

例如:

var HelloObj = new MyObject('Hello');
HelloObj.SetActive();    
    //This alerts 'SetActive: Hello'
HelloObj.ListItem1.click();    
    //This alerts 'SetActive: undefined' because 'this' in SetActive
    //becomes ListItem1 and obviously ListItem1.Name is undefined

那么我怎么能将DOM元素的事件处理程序设置为函数指针(不是每个事件处理程序的新函数实例,当有大量对象实例时效率低下),但仍然保留对象实例本身的上下文关于"this"?

试试bind():

this.ListItem1.onclick = this.SetActive.bind(this); 
//and so on

我提出的解决方案和我现在使用的是附加一个引用对象实例到DOM元素,然后使用事件处理程序的包装器函数通过该引用调用所需的函数:

MyObject = function (Name) {
  this.Name = Name;
  this.ListItem1 = document.createElement('li');
  this.ListItem1.Context = this;
  this.ListItem1.onclick = this.SetActiveHandler;
  this.ListItem2 = document.createElement('li');
  this.ListItem2.Context = this;
  this.ListItem2.onclick = this.SetActiveHandler;
}
MyObject.prototype.SetActiveHandler = function () {
  this.Context.SetActive();
}
MyObject.prototype.SetActive = function () {
  alert('SetActive: ' + this.Name);
}

这解决了我所有的问题,尽管我不完全满意,因为有一些陷阱。从视觉上看,它不那么漂亮,而且更复杂。以编程方式创建一个循环引用这我知道一般让人皱眉头,虽然在我的情况下我认为它不应该造成任何问题,我只是担心现代浏览器,而且我相信循环引用完全包含,如果所有的DOM元素从文档中删除,删除我的参考实例MyObject本身都应该完全垃圾收集(一些反馈这将不胜感激)。我知道将自定义属性附加到DOM元素也被认为是不好的做法,尽管我不知道这在现代浏览器中是否仍然是一个问题(同样,一些反馈将是伟大的)。它还稍微破坏了面向对象的流程,必须通过第二个函数,我希望将事件处理程序直接附加到SetActive()

有没有人有其他的解决方案,或者可以说明我是否实际上制造了比我解决的更多的问题?

相关文章: