(javascript)为什么我需要为事件处理程序使用wrap函数?

Ton*_*ark 3 javascript closures event-handling wrap-function

我试图理解为什么在下面的代码中我需要Dragger.prototype.wrap以及为什么我不能直接使用事件处理方法:

function Dragger(id) {
    this.isMouseDown = false;
    this.element = document.getElementById(id);
    this.element.onmousedown = this.wrap(this, "mouseDown");
}

Dragger.prototype.wrap = function(obj, method) {
    return function(event) {
        obj[method](event);
    }
}

Dragger.prototype.mouseDown = function(event) {
    this.oldMoveHandler = document.body.onmousemove;
    document.onmousemove = this.wrap(this, "mouseMove");
    this.oldUpHandler = document.body.onmousemove;
    document.onmouseup = this.wrap(this, "mouseUp");
    this.oldX = event.clientX;
    this.oldY = event.clientY;
    this.isMouseDown = true;
}

Dragger.prototype.mouseMove = function(event) {
    if (!this.isMouseDown) {
        return;
    }
    this.element.style.left = (this.element.offsetLeft
            + (event.clientX - this.oldX)) + "px";
    this.element.style.top = (this.element.offsetTop
            + (event.clientY - this.oldY)) + "px";
    this.oldX = event.clientX;
    this.oldY = event.clientY;
}

Dragger.prototype.mouseUp = function(event) {
    this.isMouseDown = false;
    document.onmousemove = this.oldMoveHandler;
    document.onmouseup = this.oldUpHandler;
}
Run Code Online (Sandbox Code Playgroud)

我被告知这是因为this没有它的更改,但我不明白为什么this更改,为什么wrap函数阻止它更改,以及this如果没有wrap函数会改变什么.

CMS*_*CMS 7

你需要包装它们,因为当一个函数被用作事件处理程序时,this关键字引用触发事件的DOM元素,如果你不包装它,你就无法访问Dragger对象的实例成员就像this.isMouseDown.

例如:

假设您有一个按钮:

<input type="button" id="buttonId" value="Click me" />
Run Code Online (Sandbox Code Playgroud)

你有以下对象:

var obj = {
  value: 'I am an object member',
  method: function () {
    alert(this.value);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果你打电话:

obj.method();
Run Code Online (Sandbox Code Playgroud)

您将看到包含在对象value成员中的文本的警报obj("我是对象成员").

如果您将该obj.method函数用作事件处理程序:

document.getElementById('buttonId').onclick = obj.method;
Run Code Online (Sandbox Code Playgroud)

当用户点击按钮时,它会提示"点击我".

为什么?因为当触发click事件时,obj.method将使用this指向DOM元素的关键字执行,并且它将提示"Click me",因为该按钮包含一个value成员.

您可以检查上面的片断跑这里.


对于上下文实施,我总是保持关闭绑定功能:

// The .bind method from Prototype.js
if (!Function.prototype.bind) {
  Function.prototype.bind = function(){
    var fn = this, args = Array.prototype.slice.call(arguments),
             object = args.shift();
    return function(){
      return fn.apply(object,
        args.concat(Array.prototype.slice.call(arguments)));
    };
  };
}
Run Code Online (Sandbox Code Playgroud)

它允许您包装任何函数,强制执行上下文.作为第一个参数,它接收将被用作的对象,this其余的可选参数是这里将调用的包装函数中心代码.

在按钮示例中,我们可以将其用作:

document.getElementById('buttonId').onclick = obj.method.bind(obj);
Run Code Online (Sandbox Code Playgroud)

它在很多情况下都非常有用,它将作为ECMAScript 5的一部分引入.

  • 对不起,你能详细说明吗?我不明白. (3认同)