Applying OOP with jQuery

2019-04-07 14:05发布

问题:

I'm working with jQuery and trying to apply some basic Javascript OOP principles to a set of functions that control hover behavior. However, I can't figure out how to get the "this" keyword to refer to the instance of the object I'm creating. My sample code is:

var zoomin = new Object();

zoomin = function() {
       // Constructor goes here
};

zoomin.prototype = {
       hoverOn: function() {
          this.hoverReset();
          // More logic here using jQuery's $(this)...
       },
       hoverReset: function() {
          // Some logic here.
       }
       };

// Create new instance of zoomin and apply event handler to matching classes.
var my_zoomin = new zoomin();
$(".some_class").hover(my_zoomin.hoverOn, function() { return null; });

The problematic line in the above code is the call to "this.hoverReset()" inside the hoverOn() function. Since "this" now refers to element that was hovered on, it does not work as intended. I would basically like to call the function hoverReset() for that instance of the object (my_zoomin).

Is there any way to do this?

Thanks!

回答1:

Only assigning a function to a property of an object does not associated this inside the function with the object. It is the way how you call the function.

By calling

.hover(my_zoomin.hoverOn,...)

you are only passing the function. It will not "remember" to which object it belonged. What you can do is to pass an anonymous function and call hoverOn inside:

.hover(function(){ my_zoomin.hoverOn(); },...)

This will make the this inside hoverOn refer to my_zoomin. So the call to this.hoverReset() will work. However, inside hoverOn, you will not have a reference to the jQuery object created by the selector.

One solution would be to pass the selected elements as parameter:

var zoomin = function() {
   // Constructor goes here
};

zoomin.prototype = {
   hoverOn: function($ele) {
      this.hoverReset($ele);
      // More logic here using jQuery's $ele...
   },
   hoverReset: function($ele) {
      // Some logic here.
   }
};


var my_zoomin = new zoomin();
$(".some_class").hover(function() { 
    my_zoomin.hoverOn($(this));  // pass $(this) to the method
}, function() { 
    return null; 
});

As a next step, you could consider making a jQuery plugin.



回答2:

  1. You can "bind" the event handler to the object (see Mootools bind code for example).
  2. You can pass the object as a parameter in the anonymous function and use that instead of this in the event handler

As for 1, you add the bind method to function

bind: function(bind){
        var self = this,
            args = (arguments.length > 1) ? Array.slice(arguments, 1) : null;

        return function(){
            if (!args && !arguments.length) return self.call(bind);
            if (args && arguments.length) return self.apply(bind, args.concat(Array.from(arguments)));
            return self.apply(bind, args || arguments);
        };
    }

Not sure though how well it will interact with JQ stuff.



回答3:

please see my answers to these questions:

where is my "this"?

why is "this" not this?

this confusion comes up all the time.

when you pass a function in as a callback, it's invoked as a standalone function, so its "this" becomes the global object.

"bind" is a native part of ecmascript 5, and is part of the function prototype. If you go to the end of my second answer up there, you get a link to the mozilla website, which has a "compatibility" version of the bind function. Use use myfunction.bind(myobject), and it'll use the native function if it's available, or the JS function if it is not.