4

我试图理解为什么在下面的代码中我需要 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;
}

我被告知这是因为this没有它会发生变化,但我不明白为什么this会发生变化,为什么 wrap 函数会阻止它发生变化,以及this没有 wrap 函数会发生什么变化。

4

2 回答 2

8

您需要包装它们,因为当函数用作事件处理程序时,this关键字指的是触发事件的 DOM 元素,如果不包装它,则无法访问Dragger对象的实例成员,喜欢this.isMouseDown

例如:

假设您有一个按钮:

<input type="button" id="buttonId" value="Click me" />

你有以下对象:

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

如果你打电话:

obj.method();

value您将看到带有包含在对象成员中的文本的警报obj“我是对象成员”)。

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

document.getElementById('buttonId').onclick = obj.method;

当用户点击按钮时,它会提示'Click me'

为什么?因为当 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)));
    };
  };
}

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

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

document.getElementById('buttonId').onclick = obj.method.bind(obj);

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

于 2009-11-20T05:59:46.367 回答
3

CMS 对this不同情况下的价值给出了很好的回答。但作为旁注,如果您不使用库或使用没有此类工具的库,您可以使用它来概括Dragger.wrap(类似于)的效果:dojo.hitch

var lockContext = function(context, callback) {
    return function() {
        callback.apply(context, arguments);
    }
};
于 2009-11-20T06:27:23.020 回答