Javascript 为什么要在构造函数中定义事件处理程序成员函数(内联),以便使用';解除绑定&x27;?
在研究的源代码时,我在构造函数函数中找到了以下代码段(请特别注意以下代码段中的注释): 。。。为了完整地提供上述代码的上下文,稍后将事件处理程序绑定为事件侦听器:Javascript 为什么要在构造函数中定义事件处理程序成员函数(内联),以便使用';解除绑定&x27;?,javascript,constructor,event-handling,Javascript,Constructor,Event Handling,在研究的源代码时,我在构造函数函数中找到了以下代码段(请特别注意以下代码段中的注释): 。。。为了完整地提供上述代码的上下文,稍后将事件处理程序绑定为事件侦听器: SignaturePad.prototype._handleMouseEvents = function () { ... this._canvas.addEventListener("mousedown", this._handleMouseDown); ... }; 从上面的代码片段中,您可以看到注释:
SignaturePad.prototype._handleMouseEvents = function () {
...
this._canvas.addEventListener("mousedown", this._handleMouseDown);
...
};
从上面的代码片段中,您可以看到注释:
我们需要添加这些内联,以便在仍然可以访问“self”的情况下可以解除绑定
我们可以使用u.bind,但不值得添加依赖项`
这件事让我抓狂。为什么解除绑定时需要访问self
(我认为解除绑定意味着分离事件侦听器,但如果我错了,请纠正我)
换句话说,我想理解上面的代码注释,这样我可以确定我完全理解了代码中的JavaScript和/或事件绑定。该代码中的
.addEventListener
调用在绑定处理程序时接收函数引用。要使用.removeEventListener
解除绑定,需要将引用传递给同一个函数处理程序
由于SignaturePad
构造函数为每个实例创建一个新的、唯一的(尽管相同)函数,并绑定该函数,因此它们需要保留对该函数的引用,以便以后解除绑定。因此,他们把它直接放在物体上以备日后使用
他们在构造函数中创建这些处理程序的原因是希望它们能够引用所创建的SignaturePad
实例。因此,它们创建一个var self=this
变量,并在构造函数引用self
中创建函数。如果处理程序位于.prototype
上,那么该共享处理程序将无法引用原始对象,因为它们的方法不同
下面是他们代码的截断版本,展示了如何使用EventListener接口:
var SignaturePad = function(canvas, options) {
this._handleMouseEvents();
};
// Implements the EventListener interface
SignaturePad.prototype.handleEvent = function(event) {
switch (event.type) {
case "mousedown":
this._handleMouseDown(event)
break
case "mousemove":
this._handleMouseMove(event)
break
case "mouseup":
this._handleMouseUp(event)
break
default:
console.log("Unbound event type:", event.type)
}
}
SignaturePad.prototype._handleMouseDown = function(event) {
if (event.which === 1) {
this._mouseButtonDown = true;
this._strokeBegin(event);
}
};
SignaturePad.prototype._handleMouseMove = function(event) {
if (this._mouseButtonDown) {
this._strokeUpdate(event);
}
};
SignaturePad.prototype._handleMouseUp = function(event) {
if (event.which === 1 && this._mouseButtonDown) {
this._mouseButtonDown = false;
this._strokeEnd(event);
}
};
SignaturePad.prototype._strokeUpdate = function(event) {
console.log("stroke update");
};
SignaturePad.prototype._strokeBegin = function(event) {
console.log("stroke begin");
};
SignaturePad.prototype._strokeEnd = function(event) {
console.log("stroke end");
};
SignaturePad.prototype._handleMouseEvents = function() {
this._mouseButtonDown = false;
this._canvas.addEventListener("mousedown", this);
this._canvas.addEventListener("mousemove", this);
document.addEventListener("mouseup", this);
};
因此,您可以看到添加了handleEvent
方法,我们实际上没有使用.addEventListener
绑定任何函数。相反,我们将引用绑定到SignaturePad
对象本身
当事件发生时,调用handleEvent
方法,其值为this
指向我们绑定的SignaturePad
对象。我们仍然可以通过event.currentTarget
访问元素
因此,这使我们能够重用
.prototype
上的函数,并为我们提供所需的所有对象引用。当然,解除绑定的方法也一样,只是我们传递绑定到的对象。removeEventListener
self
本身并不需要删除事件侦听器,但需要原始函数,因此它们保留了对它的引用。@squint谢谢。不能在构造函数外部定义\u handleMouseDown
函数,并且仍然可以删除事件侦听器吗?如果为不同的对象创建了不同的\u handleMouseDown
函数,则不能。即使函数在结构上是相同的,也需要对原始函数进行引用,因此,如果每个SignaturePad
实例都为其创建了一个单独的处理程序,那么它需要保留自己的版本……查看链接的代码,情况似乎确实如此。在SignaturePad
构造函数中创建了一个单独的处理程序,因此每个对象都有自己独特的函数,必须使用该函数解除绑定。@DanNissenbaum:most。共享事件处理程序并不是一个真正的bug。但是,他们确实希望能够从处理程序中访问SignaturePad
实例,这需要一个与他们创建的self
变量更接近的单独变量。实际上,他们最好让对象实现EventListener接口,并绑定对象本身而不是函数。然后,它们可以访问元素和处理程序。
var SignaturePad = function(canvas, options) {
this._handleMouseEvents();
};
// Implements the EventListener interface
SignaturePad.prototype.handleEvent = function(event) {
switch (event.type) {
case "mousedown":
this._handleMouseDown(event)
break
case "mousemove":
this._handleMouseMove(event)
break
case "mouseup":
this._handleMouseUp(event)
break
default:
console.log("Unbound event type:", event.type)
}
}
SignaturePad.prototype._handleMouseDown = function(event) {
if (event.which === 1) {
this._mouseButtonDown = true;
this._strokeBegin(event);
}
};
SignaturePad.prototype._handleMouseMove = function(event) {
if (this._mouseButtonDown) {
this._strokeUpdate(event);
}
};
SignaturePad.prototype._handleMouseUp = function(event) {
if (event.which === 1 && this._mouseButtonDown) {
this._mouseButtonDown = false;
this._strokeEnd(event);
}
};
SignaturePad.prototype._strokeUpdate = function(event) {
console.log("stroke update");
};
SignaturePad.prototype._strokeBegin = function(event) {
console.log("stroke begin");
};
SignaturePad.prototype._strokeEnd = function(event) {
console.log("stroke end");
};
SignaturePad.prototype._handleMouseEvents = function() {
this._mouseButtonDown = false;
this._canvas.addEventListener("mousedown", this);
this._canvas.addEventListener("mousemove", this);
document.addEventListener("mouseup", this);
};