JavaScript: bind an object's method to event handler

≡放荡痞女 提交于 2019-12-23 21:39:17

问题


According to John Resig's 'Learning Advanced JavaScript' (http://ejohn.org/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?


回答1:


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



回答2:


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

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

Note .bind requires ECMAScript >= 5




回答3:


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.




回答4:


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


来源:https://stackoverflow.com/questions/20586072/javascript-bind-an-objects-method-to-event-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!