[jQuery] return this.each
Simon, you've run into one of the more confusing things about jQuery. I
think it's safe to say that jQuery code would be easier to understand if it
used explicit function arguments everywhere instead of "this". (There are
other advantages of using "this", but it is definitely a mixed blessing.)
Every time you call a function in JavaScript (any JS code, jQuery or not),
"this" is set specifically for that function. Normally it works this way: If
the function is a method of some object, then "this" is a reference to that
object. In a function that isn't a method, "this" is a reference to the
window object. (More precisely, "this" is a reference to JavaScript's
"global object", which in a browser happens to be the window object.)
JavaScript code can also use the apply() or call() methods to call a
function and explicitly set "this" to any specific object. jQuery uses
apply() to set "this" to different things for different kinds of functions.
Inside a plugin method itself, "this" is a reference to the jQuery object
the method is operating on.
When a plugin calls this.each(), that iterates over the jQuery object and
calls a function for each DOM element in that object. Inside that callback
function, "this" is the DOM element itself.
That's why your code works when you comment out the this.each() call. Your
this.html("") and this.hover() calls are calling jQuery methods, not DOM
methods. So you need "this" to be the jQuery object - which it is when you
don't use this.each().
With the this.each() call in the code, those two innermost lines are instead
executing as part of each's callback function. Therefore, "this" is the DOM
element itself. DOM elements don't have html() and hover() methods (but you
could use this.innerHTML for example).
If you are only using other jQuery calls inside your plugin method, and you
aren't directly manipulating the DOM elements themselves., then you don't
need to call this.each() at all.
In that case you need to put "return this;" at the end of your method (and
if you have any other return statements, make them "return this;" as well).
Your method will work the same with or without, but if you leave out "return
this;" it will break the chain:
$('.foo').mycoolplugin().show();
The show() call will fail if you don't "return this;".
OTOH, if you are writing code that uses DOM methods and properties, then
you'd use this.each() in the plugin to iterate through the DOM elements.
You still need to "return this;" in such a method, but because it's a common
pattern, you can say "return this.each(...);" - the return value from the
each() call is "this", so you will be returning the right value this way.
Regarding the "var self = this;" that you see a lot of, that's needed when
an inner function needs to reach out to the outer function and see its
"this" object. For example, a plugin may use this.each() to do some work on
the DOM elements, but inside the function nested inside this.each(), it may
still need to reference the jQuery object. By setting "var self = this;" in
the outer function, the inner function can then use "self" to get to that
jQuery object. BTW, there's nothing special about the name "self" - any
variable name could be used instead.
I know that's a lot to chew on (or should I say "this" is a lot to chew
on!), so feel free to follow up with any other questions...
-Mike