18

I am creating a Javascript object that contains a function that executes a jQuery each method like the following:

function MyClass {

  Method1 = function(obj) { 
    // Does something here
  }

  Method2 = function() {
    $(".SomeClass").each(function() {

       // 1          2
       this.Method1(this);

    });
  }

}

Which object is each THIS referring to? jQuery is referring to the item returned from the each iteration. However, I would like This[1] to refer to the containing class...

How can I refer to the containing class from within the jQuery loop?

Jeff Fritz
  • 9,821
  • 7
  • 42
  • 52

4 Answers4

20

I guess you could do something like this:

function MyClass {
     Method1 = function(obj) {
         //do something here
     } 

     Method2 = function () {
          var containingClass = this;
          $(".SomeClass").each(function () {
             containingClass.Method1(this);
           });
        }
    }
}
slipset
  • 2,960
  • 2
  • 21
  • 17
  • 1
    please scope the containingClass variable to the function using the var keyword. If you don't it will go in the global namespace. – tvanfosson Jun 11 '09 at 12:41
  • 1
    Throw a var on that ContainingClass assignment, and this is gold.. to the point, and a simple modification of my posted code. – Jeff Fritz Jun 11 '09 at 12:50
  • What about when I need to do something like `$(.SomeClass).click(function(){this.Method1()/*and some other code here*/});`? – yihangho Sep 03 '13 at 05:21
12

From http://docs.jquery.com/Core/each:

This means that every time the passed-in function is executed (which is once for every element matched) the 'this' keyword points to the specific DOM element. Note that 'this' does not point to a jQuery object.

Personally, I prefer using explicit parameters. This way, it is more easily readable:

$('#rotfl').each(function(index, domObject)
{
   var jQueryObject = $(domObject);
   // code
});

To answer your question: JavaScript has dynamic static scope. You can do the following:

var that = this;
$('#rotfl').each(function(index, domObject)
{
   var jQueryObject = $(domObject);
   that.DoSomething();
   // code
});
Tamas Czinege
  • 118,853
  • 40
  • 150
  • 176
4

What you're seeing isn't an issue with jQuery or its each() method - it is it what some people consider to be a design error in JavaScript - a nested function should "inherit" the context of the previous scope, so 'this' in a nested function should be equal to 'this' in its parent scope unless purposefully called from within a different context (using apply() or call()).

To get around this you need to assign 'this' to a variable before the nested function so that you have another way to reference it.

James
  • 109,676
  • 31
  • 162
  • 175
  • It is indeed to do with jQuery.each(), which works by using call() (in the most common case) or apply() and thus changes the object that *this* refers to. – NickFitz Jun 11 '09 at 13:09
  • Yes, but even if jQuery didn't call()/apply() the function 'this' still wouldn't be what was expected. Try it (function(){(function(){ alert(!!this.works); /* Doesn't exist */ })()}).call({works:true}); – James Jun 11 '09 at 13:30
2

In jQuery 1.3.3, you will be able to manually set the context for event handlers and such.

jQuery Edge: Bind with a Different “this”

In the meanwhile, the various techniques here (aliasing "this", using call/apply) are common practise. Peter Higgins of Dojo has also made a jQuery.hitch plugin, which serves the same need.

gnarf
  • 105,192
  • 25
  • 127
  • 161
ajpiano
  • 109
  • 2