Why is the "this" inside of of the Clickers' click method referring to
the dom node rather than ... itself?
Because the specification for .addEventListener()
is to set the this
pointer to the DOM element that caught the event. That's how it is designed to work.
When passing a method as a callback where you want to override the value of this
, you can use .bind()
to force the desired value of this
with it:
this.elem.addEventListener('click', this.click.bind(this));
Explanation:
All function calls in Javascript set a new value of this
according to how the function is called. See this explanation for further info on that basic set of rules.
On top of that, when you do this:
this.elem.addEventListener('click', this.click);
You are just getting the this.click
method and passing that method alone to addEventListener()
. The value of this
will be completely lost. It's as if you are doing this:
var m = this.click; // m here is just a reference to Clicker.prototype.click
this.elem.addEventListener('click', m);
On top of this, .addEventListener()
is specifically built to set it's own value of this
when it calls the callback (to point this
at the element creating the event).
So, you can use .bind()
as shown above to force the proper value of this
to be in place when your method is called.
For reference, you may find this description of the six ways that this is set for a function call in Javascript to be useful.
Other Options
I find .bind()
to be the clearest way of defining this, but you could also use either a local anonymous function:
var self = this;
this.elem.addEventListener('click', function() {
self.click();
});
or in ES6, an arrow function:
this.elem.addEventListener('click', () => this.click());
The arrow function will preserve the value of this
for you automatically to avoid needing the self
reference used in the prior example.