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?

+3


source to share


3 answers


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

      

+2


source


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.

+3


source


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

-1


source







All Articles