tags:

views:

92

answers:

6

The following put the id name of each div inside the div as content:

        <div id="divDiv">

        </div>

        <div id="divLink">

        </div>
[...]

$('div').each(function() { $(this).prepend($(this).attr('id')) })

will work but

$('#divStatus div').prepend($(this).attr('id'))

will not. Why is that? I thought $(this) is the loop variable? Is there a way to do the above without using each() ?

+1  A: 

$(this) is just a jquery wrapper for the currently used object.

And in your first sample you are iterating through objects and you can access this, but in your second sample it will return a collection of object and you can't use this directly on them.

See The this keyword

rahul
This is incorrect, `this` likely refers to `document` in his second example...it's not that it's a collection, actually it's *rarely* a collection. Not downvoting, but you should fix this :)
Nick Craver
Actually it was a typo and was about to type **you can't**. Fixing it
rahul
@rahul - I see the typo...but it's still incorrect "your second sample it will return a collection of object" is the part I was referring to :)
Nick Craver
A: 

Hi there.

Try:

.prepend(function(idx, element){


})

.prepend( function(index, html) ) function(index, html)A function that returns an HTML string to insert at the beginning of each element in the set of matched elements. Receives the index position of the element in the set and the old HTML value of the element as arguments.

Other then this, I can't see how you can iterate over elements using the $(this) object without an actual iteration source.

Cheers. Jas.

Jason Evans
A: 

At the point you use 'this' 'this' is group of elements as an array/object so really you need to use:

$('#divStatus div')[0]

or

$('#divStatus div').get(0)

to get the first element in the array. You should be able to see what this is by using console.log(this) in firebug.

matpol
+2  A: 

Ok, think about this in terms of a regular programming language (which it is, because it's JavaScript). You are calling the "prepend" method of the 'some_object_here'.

What parameters are you telling the JavaScript engine to pass into the method BEFORE RUNNING IT? The answer is simple, you are telling JavaScript to immediately evaluate the value of "$(this).attr('id')" and then pass that into the method.

The reason why you get the desired result with the "each" is that you are passing in a function that will be evaluated later, when the context tells the JavaScript engine that "this" means the current object (which at that time is the actual div itself).

Timothy Khouri
+2  A: 

when using .each you pass a function as an argument. jQuery makes sure this is correct in its context.

When calling .prepend($(this).attr('id')), JavaScript evaluates the id before calling prepend. Asuuming you're in $(document).ready, and the document doesn't have an ID, it is the same as calling .prepend("");.

Kobi
A: 

This is called a closure, unfortunately no other answers contain this very important keyword. I recommend reading this question: How does a javascript closure work ? and this article.

.each() creates a closure, .prepend(), unless you're passing a function, doesn't, though it can take a function to solve your current issue, like this:

$('#divStatus div').prepend(function() {
  return $(this).attr('id'); //or this.id if you're sure it has one
});

Inside these closures this refers to the element in the array you're on, outside them, it refers to whatever context you're in, for example:

$(function() { //short for $(document).ready(function() {
  $('#divStatus div').prepend($(this).attr('id')) //this refers to document
});

A jQuery object is an array inside, an array of references to DOM elements, whether from a selector finding them, manually added, etc. The functions that loop though these, either .each() or passing a function to various others, .prepend(), .attr(), .css(), etc all create closures in which this refers to the element in the array you're currently on when looping through.

I can't stress reading that question and article enough to get a clearer understanding of this, might clear up a few other questions you have as well.

Nick Craver
Other answers don't contain the word closure because it's not a case of a closure. It's a case of context switch for the `this` keyword, but nothing is being closed up.
deceze
@deceze - The `.each()` option [creates a closure](http://github.com/jquery/jquery/blob/master/src/core.js#L537)...that's why you're passing in a function....the second example doesn't it *is the primary difference* here, not sure how you you could think it's not relevant...
Nick Craver
The effect of a closure has not much to do with this though. The difference why one works and the other doesn't is the object `this` points to, which is a different story.
deceze
@deceze - I recommend you read the articles I linked, if it weren't for the closure, `this` wouldn't change...
Nick Craver
Yes, there is a closure being created by `function`, but it has nothing to do with the question. From your article: `Two one sentence summaries: 1) a closure is the local variables for a function kept alive after the function has returned 2) a closure is a stack-frame which is not deallocated when the function returns.` I don't see how this pertains to `this`. If `this` *was* "closured", neither example would work. :)
deceze
@deceze - First, `.each()` *does* create a different stack frame, it's a different scope. When you call one function from another, that's another frame on the stack. No offense, but you have some basic misunderstandings of the closure concept, `.each()` is internally `jQuery.each()`, which is calling `callback.apply()`, callback being the function passed in. The first argument of [`.apply()`](https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Function/Apply) is the context, what `this` will be in the closure, in this case: the **current object** in the array as you loop.
Nick Craver
And `callback.apply()` is the reason `this` works as it does. That there's a closure involved doesn't really matter. `this` could be set to the same object it was in the higher scope. Talking about closures usually means talking about "closed up" variables from a higher scope, which is not the case here. I understand your point about there being a closure, please understand my point as well. :)
deceze
@deceze - How would you do `.apply()` *without* a closure? There is no `this=something` call, it's **because** it's a closure that `this === the current element`, they *are* "closed up" from a higher scope, a variable inside the `.each()` callback is *not* accessible outside it. You're 100% backwards here, these *are* locally scoped variables, **to this closure**. I'm not sure how to explain it any more plainly than I already have. Again, I suggest you read the links I provided, you have some major misconceptions of closures here.
Nick Craver