This question already has an answer here:
-
Dealing with Scope in Object methods containing 'this' keyword called by Event Listeners
3 answers
I am probably doing something wrong but I found some interesting behavior when trying to apply some object oriented programming to Javascript. Consider the following
function Bug(element) {
this.focusedCell = null;
element.addEventListener('click', this.onClick, true);
};
Bug.prototype.onClick = function(event){
console.log("this is: ");
console.log(this);
};
When I call the method from the console, I see the correct instance of "this" but when I click the element in the document I see the document element in lieu of the instance. So... chances are it's probably not a good idea to use event listeners with instance methods, at least the way I'm doing it.
So the question is:
Is it possible to have an event listener like this that calls an instance method of a javascript object, while preserving the instance in the call?
Is there a better pattern for doing this?
Edit:
I haven't tried this in anything but Chrome. But I would imagine that the behavior is the same.
There's a better pattern, and doesn't require much change. I'll show the code first.
function Bug(element) {
this.focusedCell = null;
// --------------------------------v----pass the object, not a function
element.addEventListener('click', this, true);
};
// Implement the `EventListener` interface
Bug.prototype.handleEvent = function(event) {
if (event.type === "click")
this.onClick(event);
}
Bug.prototype.onClick = function(event) {
console.log(JSON.stringify(this)); // '{"focusedCell":null}'
console.log(event.currentTarget.nodeName); // "DIV"
};
By adding the handleEvent
method, we make Bug
implement the EventListener
interface. This allows us to pass the new Bug
object as the second argument to addEventListener()
instead of a function.
Now when the "click"
event happens, the .handleEvent()
method will be invoked, and the value of this
in that method will be the Bug
object that was bound.
Since this
is a reference to the Bug
instance, it obviously won't be a reference to the element anymore. But it's not necessary, since the element is available via event.currentTarget
.
Of course, you could add the element directly to your Bug
object in the constructor if desired.
DEMO: http://jsfiddle.net/CnZTa/
You can use Function.prototype.bind
to create a listener bound to whatever this value you want:
function Bug(element) {
this.focusedCell = null;
element.addEventListener('click', this.onClick.bind(this), true);
};
Older (non-ES5) browsers will need a polyfill such as the one from MDN.
This is normal behavior in JavaScript. You can preserve your expected this
by passing an function the the listener:
function Bug(element) {
var self = this; // Store a reference to this
this.focusedCell = null;
element.addEventListener('click', function() {
// in here this refers to element
self.onClick(event);
}, true);
};
Bug.prototype.onClick = function(event){
console.log("this is: ");
console.log(this); // In here this refers the an instance of Bug.
};