在研究a signature pad widget的源代码时,我在构造函数中找到以下代码段(请注意以下代码段中的注释):
var SignaturePad = function (canvas, options) {
...
// MY QUESTION IS ABOUT THE FOLLOWING CODE COMMENT!!!
// v v v
// we need add these inline so they are available to unbind while still having
// access to 'self' we could use _.bind but it's not worth adding a dependency
this._handleMouseDown = function (event) {
if (event.which === 1) {
self._mouseButtonDown = true;
self._strokeBegin(event);
}
};
// ... other event handlers here
...
}
...为完整性提供上述代码的上下文,稍后将事件处理程序绑定为事件侦听器:
SignaturePad.prototype._handleMouseEvents = function () {
...
this._canvas.addEventListener("mousedown", this._handleMouseDown);
...
};
从上面的代码段中,您可以看到评论:
我们需要添加这些内联,以便在仍然可以访问“self”
时解除绑定我们可以使用_.bind,但不值得添加依赖
我对此感到头疼。为什么在解除绑定时需要访问self
(我假设'解绑'意味着分离事件监听器,但如果我错了请纠正我)?
换句话说,我想了解上面的代码注释,以便我可以确定我在此代码中彻底理解了JavaScript和/或事件绑定。
答案 0 :(得分:2)
该代码中的.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
的对象之外,取消绑定的方式相同。