0

在我的 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元素的事件处理程序设置为函数指针(不是每个事件处理程序的新函数实例,当有大量对象实例时效率低下)但仍然保留对象实例本身的上下文'这'?

4

2 回答 2

1

试试bind()这样:

this.ListItem1.onclick = this.SetActive.bind(this); 
//and so on
于 2013-03-28T16:44:31.640 回答
0

我提出并现在使用的解决方案是将对象实例的引用附加到 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().

有没有人有任何其他的解决方案,或者可以阐明我是否真的创造了比我解决的问题更多的问题?

于 2013-03-28T18:56:59.733 回答