Reputation: 528
I'm trying to create an event for an object to have it listen to it. Consider the following example:
var moon;
moon = document.createEvent("Event");
moon.initEvent("Event",true,true);
var Dog = function (name) {
this.name = name;
document.addEventListener("Event",this.bark,false);
};
dog.prototype.bark = function() {
console.log(this.name + ': Awooooooof Woof!');
};
var spot = new Dog("Spot");
var dot = new Dog("Dot");
//invoke
document.dispatchEvent(moon);
I'm expecting to receive an output like:
Spot: Awooooooof Woof!
Dot: Awooooooof Woof!
But what I get is:
undefined: Awooooooof Woof!
What is wrong with my example? How can I register a listener that every instance of Dog has?
Upvotes: 9
Views: 8746
Reputation: 9997
The Problem
The this
keyword, inside Dog.prototype.bark()
points to the object that invoked the method. For example, when spot.bark()
is called, this.name
evaluates to spot.name
, like so:
Dog.prototype.bark = function () {
console.log(spot.name + ': Awooooooof Woof!');
};
When the event listener is added inside Dog's constructor, the document
object is told to listen for that event, and told to call Dog.prototype.bark()
when it hears that event. This setup is done correctly and the document
object will call the correct function when it hears that event,
The trouble happens later when the document
object actually calls the bark function. Now, this
points to the document
object, and this.name
evaluates to document.name
, like so:
Dog.prototype.bark = function () {
console.log(document.name + ': Awooooooof Woof!');
};
document.name
doesn't exist and that's why the output is: undefined: Awooooooof Woof!
The Fix
Use Function.prototype.bind() to bind the provided value to a function's this
keyword, like so:
document.addEventListener("Moon", this.bark.bind(this), false);
Upvotes: 0
Reputation: 24551
In this line
document.addEventListener("Event",this.bark,false);
you don't bind the scope of this.bark
to this
. In JavaScript, the value of this
does not depend on where the function is defined but from where it is called. This means when you pass this.bark
to addEventListener
you detach it from the current object.
In frameworks like prototype.js and JQuery there are shortcuts for binding this
, with vanilla JavaScript you can do it like this:
function bind(scope, fn) {
return function() {
return fn.apply(scope, arguments);
}
}
And then:
document.addEventListener("Event",bind(this, this.bark),false);
Upvotes: 10
Reputation: 17146
The problem you have is that this
inside the function does not refer to the object you want to manipulate.
How about adding the function bark
inside the function definition?
var Dog = function (name) {
this.name = name;
this.bark = function() {
console.log(name + ': Awooooooof Woof!');
};
document.addEventListener("Event", this.bark, false);
};
Upvotes: 4