JavaScript:将对象的方法绑定到事件处理程序

时间:2013-12-14 17:23:02

标签: javascript event-handling

根据John Resig的“学习高级JavaScript”(http://ejohn.org/apps/learn/#83),将对象的方法绑定到事件处理程序而不将原始对象作为上下文传递是不正确的,但我发现该示例存在缺陷。它声称被点击的属性被意外设置。这是一个反例。

var Button = {
  click: function(){
    this.clicked = true;
    console.log( elem.clicked );
  }
};

var elem = document.createElement("li");
elem.innerHTML = "Click me!";
elem.onclick = Button.click;
document.children[0].appendChild(elem);

console.log( !elem.clicked );

必须有另一个不这样做的理由。它是什么?

4 个答案:

答案 0 :(得分:7)

在任何对象方法中,this始终引用调用方法的对象this提供调用上下文的所有JavaScript都是如此,而不是方法所有者 (*)

var sample = {
    foo: function () {
        this.clicked = true;
    }
}

sample.foo();         // 'this' refers to 'sample' 
alert(sample.clicked) // true

在事件处理程序this中引用触发事件的元素。这意味着当您将对象方法传递给click事件...

var div = document.getElementById("test");
div.onclick = sample.foo;

然后{<1}}将在 DOM元素上调用,即使它已在别处定义。

foo()

这将导致意想不到的结果。


(*)这是因为从技术上讲,JavaScript中没有方法所有者。方法是恰好由对象属性引用的独立函数。在不同的对象中存储对同一函数的引用(/* ... click the div ... */ alert(sample.clicked); // false alert(div.clicked); // true 就是这样)很容易实现。

因此,div.onclick = sample.foo是句法糖。

obj.method()

答案 1 :(得分:3)

您也可以使用Function.prototype.bind来解决此问题

elem.onclick = Button.click.bind(Button);

注意 .bind需要ECMAScript >= 5

答案 2 :(得分:2)

Resig先生所说的是,在JavaScript中,this的获取方式与this在其他语言中的工作方式明显不同。在这个例子中,我认为他的观点是在“Button”对象上的“click”函数中对this的引用不一定是指该对象。相反,它的值仅由调用函数的情况决定。

因此,当您将该函数用作事件处理程序时,函数中this的值将是对所单击元素的引用。

答案 3 :(得分:0)

这是一个简单的例子,没有事件。

var foo = {
  method: function() {
    this.prop = true;
  }
};

var bar = {};

bar.method = foo.method;
bar.method();

console.log( foo.prop ); // => undefined
console.log( bar.prop ); // => true

foo.method();

console.log( foo.prop ); // => true

在您的示例中,您似乎在点击元素之前检查elem.clicked 的状态。单击它,属性将被设置(但Button.clicked不会被设置!)。正确的方法是:

elem.onclick = function() { Button.click(); };