About closure when using jQuery hover method?
My code:
function Demo (){
this.name = 'abc';
this.age = 20;
}
var demo = {
init : function(){
$('#test').hover(this.stop, this.start);
},
start: function(){
//here is the error
alert(this.name);
}
stop: function(){
alert(this.age); // 'this' does not mean the Demo object, but $('#test') object.
}
}
Demo.prototype = demo;
Demo.prototype.constructor = Demo;
(new Demo).init();
When the hover $ ('# test') event fires, the stop method is called. However, the 'this' in the method does not point to the demo object, but the $ ('# test') object. So the warning is undefined. I need to be able to access the attributes in the Demo object. And the stop and start method will be reused elsewhere, so I don't like writing all the method code in the hover argument. How can I solve this problem?
source to share
JQuery uses apply
behind the scenes to call event callbacks, so the context changes.
To mitigate this, you can do one of two things:
Use bind
var demo = {
init : function(){
$('#test').hover(this.stop.bind(this), this.start.bind(this));
},
start: function(){
alert(this.name);
}
stop: function(){
alert(this.age);
}
}
method call directly
var demo = {
init : function(){
// Closure here
var self = this;
$('#test').hover(function() {
self.stop();
}, function() {
self.start();
});
},
start: function(){
alert(this.name);
}
stop: function(){
alert(this.age);
}
}
source to share
this
in methods start
and stop
does not necessarily point to the same this
as init
. This is because they are callback functions. If you want to refer to the same object context, try this:
var demo = {
init : function(){
$('#test').hover(this.stop.bind(this), this.start.bind(this));
},
start: function(){
//here is the error
alert(this.name);
}
stop: function(){
alert(this.age); // 'this' does not mean the Demo object, but $('#test') object.
}
}
Usage bind
will pass the context this
through callbacks.
MDN docs for bind here.
source to share
A No JSON implementation that will allow you to set the self variable
function Demo(){
this.name = 'abc';
this.age = 20;
}
Demo.prototype = new (function(){
var self = this;
this.init = function(){
$('#test').hover(self.stop, self.start);
}
this.start = function(){
//here is the error
alert(self.name);
}
this.stop = function(){
alert(self.age); // 'this' does not mean the Demo object, but $('#test') object.
}
})();
(new Demo()).init()
EDIT: I updated to show what I meant without using the var demo = {...}
point I was trying to do is not to use Object Literal
aka JSON style so you can maintain a variable inside a prototype
source to share