使用 addEventListener 的处理程序中“this”的值

新手上路,请多包涵

我通过原型制作创建了一个 Javascript 对象。我正在尝试动态呈现表格。虽然呈现部分很简单并且工作正常,但我还需要为动态呈现的表处理某些客户端事件。那,也很容易。我遇到问题的地方是处理事件的函数内的“this”引用。 “this”不是引用对象,而是引用引发事件的元素。

见代码。有问题的区域在 ticketTable.prototype.handleCellClick = function()

 function ticketTable(ticks)
{
    // tickets is an array
    this.tickets = ticks;
}

ticketTable.prototype.render = function(element)
    {
        var tbl = document.createElement("table");
        for ( var i = 0; i < this.tickets.length; i++ )
        {
            // create row and cells
            var row = document.createElement("tr");
            var cell1 = document.createElement("td");
            var cell2 = document.createElement("td");

            // add text to the cells
            cell1.appendChild(document.createTextNode(i));
            cell2.appendChild(document.createTextNode(this.tickets[i]));

            // handle clicks to the first cell.
            // FYI, this only works in FF, need a little more code for IE
            cell1.addEventListener("click", this.handleCellClick, false);

            // add cells to row
            row.appendChild(cell1);
            row.appendChild(cell2);

            // add row to table
            tbl.appendChild(row);
        }

        // Add table to the page
        element.appendChild(tbl);
    }

    ticketTable.prototype.handleCellClick = function()
    {
        // PROBLEM!!!  in the context of this function,
        // when used to handle an event,
        // "this" is the element that triggered the event.

        // this works fine
        alert(this.innerHTML);

        // this does not.  I can't seem to figure out the syntax to access the array in the object.
        alert(this.tickets.length);
    }

原文由 Darthg8r 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 612
2 个回答

您需要将处理程序“绑定”到您的实例。

 var _this = this;
function onClickBound(e) {
  _this.handleCellClick.call(cell1, e || window.event);
}
if (cell1.addEventListener) {
  cell1.addEventListener("click", onClickBound, false);
}
else if (cell1.attachEvent) {
  cell1.attachEvent("onclick", onClickBound);
}

请注意,此处的事件处理程序规范化 event 对象(作为第一个参数传递)并在适当的上下文中调用 handleCellClick (即引用附加事件侦听器的元素)。

另请注意,此处的上下文规范化(即在事件处理程序中设置正确的 this )在用作事件处理程序的函数( onClickBound )和元素对象( cell1 )之间创建了一个循环引用 --- )。在某些版本的 IE(6 和 7)中,这可能并且可能会导致内存泄漏。这种泄漏本质上是由于本机对象和宿主对象之间存在循环引用,导致浏览器无法在页面刷新时释放内存。

要规避它,您需要 a) drop this normalization; b) 采用替代的(和更复杂的)规范化策略; c)“清理”页面卸载时的现有事件监听器,即使用 removeEventListenerdetachEvent 和元素 null 导航无用)。

您还可以找到一个 JS 库来处理这个问题。它们中的大多数(例如:jQuery、Prototype.js、YUI 等)通常按照 © 中的描述处理清理。

原文由 kangax 发布,翻译遵循 CC BY-SA 2.5 许可协议

您可以使用 bind ,它可以让您指定在对给定函数的所有调用中应用作 this 的值。

    var Something = function(element) {
      this.name = 'Something Good';
      this.onclick1 = function(event) {
        console.log(this.name); // undefined, as this is the element
      };
      this.onclick2 = function(event) {
        console.log(this.name); // 'Something Good', as this is the binded Something object
      };
      element.addEventListener('click', this.onclick1, false);
      element.addEventListener('click', this.onclick2.bind(this), false); // Trick
    }

上面示例中的一个问题是您无法使用绑定删除侦听器。另一种解决方案是使用一个名为 handleEvent 的特殊函数来捕获任何事件:

 var Something = function(element) {
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // 'Something Good', as this is the Something object
    switch(event.type) {
      case 'click':
        // some code here...
        break;
      case 'dblclick':
        // some code here...
        break;
    }
  };

  // Note that the listeners in this case are this, not this.handleEvent
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // You can properly remove the listners
  element.removeEventListener('click', this, false);
  element.removeEventListener('dblclick', this, false);
}

像往常一样, mdn 是最好的 :)。我只是复制粘贴部分而不是回答这个问题。

原文由 gagarine 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题