Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript “的价值”;这";在使用addEventListener的处理程序中_Javascript_Oop_Dom Events - Fatal编程技术网

Javascript “的价值”;这";在使用addEventListener的处理程序中

Javascript “的价值”;这";在使用addEventListener的处理程序中,javascript,oop,dom-events,Javascript,Oop,Dom Events,我已经通过原型创建了一个Javascript对象。我正在尝试动态呈现一个表。虽然呈现部分很简单且工作正常,但我还需要为动态呈现的表处理某些客户端事件。那也很容易。我遇到的问题是处理事件的函数内部的“this”引用。不是“this”引用对象,而是引用引发事件的元素 参见代码。问题区域位于ticketTable.prototype.handleCellClick=function(): function ticketTable(ticks) { // tickets is an array

我已经通过原型创建了一个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);
    }
功能票证(滴答声)
{
//票是一个数组
this.tickets=滴答声;
} 
ticketTable.prototype.render=函数(元素)
{
var tbl=document.createElement(“表”);
for(var i=0;i
您需要将处理程序“绑定”到实例

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);
}
请注意,这里的事件处理程序规范化
事件
对象(作为第一个参数传递),并在适当的上下文中调用
handleCellClick
(即引用附加到事件侦听器的元素)

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

为了避免这种情况,您需要a)删除
这个
规范化;b) 采用替代的(更复杂的)规范化策略;c) “清理”页面卸载上的现有事件侦听器,即通过使用
removeEventListener
detachEvent
和元素
null
ing(不幸的是,这会使浏览器的快速历史导航无效)


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

我知道这是一篇较老的文章,但您也可以简单地将上下文分配给变量
self
,将您的函数放入一个匿名函数,该函数使用
调用您的函数。调用(self)
并在上下文中传递

ticketTable.prototype.render = function(element) {
...
    var self = this;
    cell1.addEventListener('click', function(evt) { self.handleCellClick.call(self, evt) }, false);
...
};

这比“接受答案”更有效,因为上下文不需要为整个类或全局分配变量,而是整齐地隐藏在侦听事件的同一方法中。

此外,还有一种方法是使用(来自DOM2!!我想知道为什么没有人提到它,因为这是最整洁的方式,适合这种情况。)

也就是说,不是传递回调函数,而是传递一个实现EventListener接口的对象,它指向事件处理程序函数。这里的主要区别是,在函数内部,
this
将引用传递给
addEventListener
的对象。也就是说,
this。ticketTable
将是下面代码中的对象实例。要理解我的意思,请仔细查看修改后的代码:

ticketTable.prototype.render = function(element) {
...
var self = this;

/*
 * Notice that Instead of a function, we pass an object. 
 * It has "handleEvent" property/key. You can add other
 * objects inside the object. The whole object will become
 * "this" when the function gets called. 
 */

cell1.addEventListener('click', {
                                 handleEvent:this.handleCellClick,                  
                                 theTicketTable:this
                                 }, false);
...
};

// note the "event" parameter added.
ticketTable.prototype.handleCellClick = function(event)
{ 

    /*
     * "this" does not always refer to the event target element. 
     * It is a bad practice to use 'this' to refer to event targets 
     * inside event handlers. Always use event.target or some property
     * from 'event' object passed as parameter by the DOM engine.
     */
    alert(event.target.innerHTML);

    // "this" now points to the object we passed to addEventListener. So:

    alert(this.theTicketTable.tickets.length);
}
您可以使用它来指定对给定函数的所有调用都应使用的值

   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
    }
上面示例中的一个问题是无法使用bind删除侦听器。另一个解决方案是使用名为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);
}

喜欢总是最好的:)。我只是复制粘贴了这个部分,而不是回答这个问题。

深受卡玛特伦和加加林回答的影响,我想我可能会解决这个问题

我在想,如果您将handeCellClick放在回调列表中,并使用事件上使用EventListener接口的对象触发回调列表方法,您可能会获得更多的自由

function ticketTable(ticks)
    {
        // tickets is an array
        this.tickets = ticks;
        // the callback array of methods to be run when
        // event is triggered
        this._callbacks = {handleCellClick:[this._handleCellClick]};
        // assigned eventListenerInterface to one of this
        // objects properties
        this.handleCellClick = new eventListenerInterface(this,'handleCellClick');
    } 

//set when eventListenerInterface is instantiated
function eventListenerInterface(parent, callback_type) 
    {
        this.parent = parent;
        this.callback_type = callback_type;
    }

//run when event is triggered
eventListenerInterface.prototype.handleEvent(evt)
    {
        for ( var i = 0; i < this.parent._callbacks[this.callback_type].length; i++ ) {
            //run the callback method here, with this.parent as
            //this and evt as the first argument to the method
            this.parent._callbacks[this.callback_type][i].call(this.parent, evt);
        }
    }

ticketTable.prototype.render = function(element)
    {
       /* your code*/ 
        {
            /* your code*/

            //the way the event is attached looks the same
            cell1.addEventListener("click", this.handleCellClick, false);

            /* your code*/     
        }
        /* your code*/  
    }

//handleCellClick renamed to _handleCellClick
//and added evt attribute
ticketTable.prototype._handleCellClick = function(evt)
    {
        // this shouldn't work
        alert(this.innerHTML);
        // this however might work
        alert(evt.target.innerHTML);

        // this should work
        alert(this.tickets.length);
    }
功能票证(滴答声)
{
//票是一个数组
this.tickets=滴答声;
//要在以下情况下运行的方法的回调数组:
//事件被触发
this.\u callbacks={handleCellClick:[this.\u handleCellClick]};
//已将eventListenerInterface分配给其中一个
//对象属性
this.handleCellClick=新的eventListenerInterface(this,'handleCellClick');
} 
//在实例化eventListenerInterface时设置
函数eventListenerInterface(父级,回调类型)
{
this.parent=parent;
this.callback\u type=callback\u type;
}
//在触发事件时运行
...
    cell1.addEventListener("click", this.handleCellClick.bind(this));
...

ticketTable.prototype.handleCellClick = function(e)
    {
        alert(e.currentTarget.innerHTML);
        alert(this.tickets.length);
    }
var something = function(element) {
  this.name = 'Something Good';
  this.onclick1 = function(event) {
    console.log(this.name); // 'Something Good'
  };
  element.addEventListener('click', () => this.onclick1());
}
document.addEventListener('click', (event) => {
  // do stuff with event
  // do stuff with this 
});