javascript - 为什么要在构造函数中定义事件处理程序成员函数(内联)以便与 'unbind' 一起使用?

标签 javascript constructor event-handling

在研究 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

    ...

}

...为了为上述代码提供上下文的完整性,稍后将事件处理程序绑定(bind)为事件监听器:

SignaturePad.prototype._handleMouseEvents = function () {
    ...
    this._canvas.addEventListener("mousedown", this._handleMouseDown);
    ...
};

从上面的代码片段中,可以看到注释:

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`

我正在为这个问题挠头。为什么在解除绑定(bind)时需要访问 self(我假设“解除绑定(bind)”意味着分离事件监听器,但如果我错了请纠正我)?

换句话说,我想理解上面的代码注释,以便我可以确定我完全理解这段代码中的 JavaScript 和/或事件绑定(bind)。

最佳答案

该代码中的 .addEventListener 调用在绑定(bind)处理程序时接收函数引用。为了使用 .removeEventListener 解除绑定(bind),您需要传递对相同函数处理程序的引用。

因为 SignaturePad 构造函数为每个实例创建了一个新的、唯一的(尽管相同)函数,并绑定(bind)了该函数,所以它们需要保留对该函数的引用以便稍后解除绑定(bind)。因此,他们将其直接放在对象上以备后用。

他们在构造函数中创建这些处理程序的原因是他们希望它们能够引用创建的 SignaturePad 实例。所以他们创建了一个 var self = this 变量,并让在构造函数中创建的函数引用 self。如果处理程序位于 .prototype 上,则共享处理程序将无法引用原始对象,因为它们采用了这种方法。


这是他们代码的 chop 版本,展示了如何使用 EventListener 接口(interface):

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绑定(bind)任何函数。相反,我们将引用绑定(bind)到 SignaturePad 对象本身。

当事件发生时,handleEvent 方法被调用,this 的值指向我们绑定(bind)的 SignaturePad 对象。我们仍然可以通过 event.currentTarget 访问该元素。

因此,这让我们可以重用 .prototype 上的函数,并为我们提供所需的所有对象引用。当然,解除绑定(bind)也是以同样的方式完成的,除了我们将绑定(bind)的对象传递给 .removeEventListener

关于javascript - 为什么要在构造函数中定义事件处理程序成员函数(内联)以便与 'unbind' 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35963702/

相关文章:

c++ - 默认构造函数 C++ 错误

c++ - 在构造函数中调用类成员的构造函数

jQuery ajax $.post 从验证插件调用时刷新页面

javascript - 为什么这个 <li> 上的事件处理程序没有被调用?

javascript - facebook-api - 如何以尽可能少的调用和尽可能稳健的方式检索用户 friend 的所有事件?

javascript - Vis.js 时间线 - 如何在不嵌套的情况下折叠组

c++ - 没有默认构造函数的对象数组初始化

javascript - 依次调用 Angular2 函数

javascript - 它是 Ecmascript 中的错误 -/\S/.test(null) 返回 true 吗?

javascript - jquery 文档级 onmousedown 在元素的单击处理程序之前被调用