【问题标题】:(javascript) why do i need to use a wrap function for event handlers?(javascript) 为什么我需要为事件处理程序使用包装函数?
【发布时间】:2009-11-20 05:54:06
【问题描述】:

我试图理解为什么在下面的代码中我需要 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 函数的情况下会变成什么。

【问题讨论】:

  • 您的标题暗示的问题与您的问题内容不同。您想了解事件处理程序、给定范围内this 的值还是prototype 的类定义?

标签: javascript closures event-handling wrap-function


【解决方案1】:

你需要包装它们,因为当一个函数用作事件处理程序时,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();

您将看到一条警报,其文本包含在 obj 对象的 value 成员中('我是对象成员')。

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

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

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

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

可以查看上面运行here的sn-ps。


为了执行上下文,我总是关闭 bind 函数:

// 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 的对象,其余可选参数是此处包装的函数输入代码将被调用的参数。

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

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

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

【讨论】:

  • 抱歉,您能详细说明一下吗?我不明白。
  • 啊,所以区别在于 'this' 将引用 DOM 对象本身,而不是处理程序(因此我无法访问 this.isMouseDown 之类的东西,因为
    没有'没有 isMouseDown 但我的类 Dragger 有?)
  • @hatorade:没错,你明白了。
  • 是因为闭包,对象中声明的方法才获得对象'this',因为它保留了它的制作环境?
  • 我认为看到对象字面量而不是实例化对象可能会让人感到困惑。
【解决方案2】:

CMS gave a good answer 关于this 在不同上下文中的值。但附带说明一下,如果您不使用库或使用没有此类工具:

var lockContext = function(context, callback) {
    return function() {
        callback.apply(context, arguments);
    }
};

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签