views:

525

answers:

4

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?

+7  A: 

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
please scope the containingClass variable to the function using the var keyword. If you don't it will go in the global namespace.
tvanfosson
-1 JavaScript 101: use var!!!!!
J-P
Throw a var on that ContainingClass assignment, and this is gold.. to the point, and a simple modification of my posted code.
Jeff Fritz
+7  A: 

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
});
DrJokepu
I like the detail of your response...
Jeff Fritz
Urm, don't you mean lexical scope, not dynamic?
J-P
J-P: Yes. Thanks for pointing it out.
DrJokepu
+1  A: 

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.

J-P
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
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});
J-P
A: 

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.

ajpiano