最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

JavaScript: bind an object's method to event handler - Stack Overflow

programmeradmin2浏览0评论

According to John Resig's 'Learning Advanced JavaScript' () it's incorrect to bind an object's method to event handler without passing the original object as context, however I find the example flawed. It claims the clicked property gets set accidentally. Here's a counter-example.

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 );

There must be another reason not to do this. What is it?

According to John Resig's 'Learning Advanced JavaScript' (http://ejohn/apps/learn/#83) it's incorrect to bind an object's method to event handler without passing the original object as context, however I find the example flawed. It claims the clicked property gets set accidentally. Here's a counter-example.

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 );

There must be another reason not to do this. What is it?

Share Improve this question asked Dec 14, 2013 at 17:23 Ivan VashchenkoIvan Vashchenko 1,2242 gold badges11 silver badges20 bronze badges 3
  • What do you mean? That code will set the "clicked" property of the <li>. – Pointy Commented Dec 14, 2013 at 17:32
  • Also you skipped the very important line of code in that example, where the "click" event was actually triggered. In your code above, the "click" function will never even be called. – Pointy Commented Dec 14, 2013 at 17:35
  • it's not "wrong" if it works, it's just potentially confusing to other coders... – dandavis Commented Dec 14, 2013 at 18:09
Add a ment  | 

4 Answers 4

Reset to default 9

In any object method, this always refers to the object the method has been called on. It's true for all JavaScript that this provides the calling context, not the method owner (*).

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

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

In an event handler this refers to the element that triggered the event. This means when you pass an object method to the click event...

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

then foo() will be called on the DOM element, even though it has been defined elsewhere.

/* ... click the div ... */ 

alert(sample.clicked); // false
alert(div.clicked);    // true

which will lead to unexpected results.


(*) That's because technically there is no method owner in JavaScript. Methods are standalone functions that happen to be referenced by object properties. Storing a reference to the same function in a different object (div.onclick = sample.foo does just that) is easily possible.

Consequently, obj.method() is syntactic sugar.

function func() { /* ... */ }
var obj = {
    method: func
};

obj.method();
func.call(obj);  // same thing

You can also use Function.prototype.bind to get around this

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

Note .bind requires ECMAScript >= 5

What Mr. Resig is talking about is the fact that in JavaScript, this gets a value in a way that's distinctly different from how this works in some other languages. In this example, I think his point is that the reference to this in the "click" function on that "Button" object doesn't necessarily refer to that object. Instead, its value is determined only by the situation in which the function is called.

Thus, when you use that function as an event handler, the value of this in the function will be a reference to the element that was clicked.

Here's a simple example, without events.

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

It seems like in your example, you're checking the state of elem.clicked before clicking the element. Click it, and the property will get set (but Button.clicked won't be set!). The correct way to do this is simply:

elem.onclick = function() { Button.click(); };
发布评论

评论列表(0)

  1. 暂无评论