2
(function(value) {
    this.value = value;
    $('.some-elements').each(function(elt){
        elt.innerHTML = this.value;        // possibly undefined (Why?)
    });
})(2);

Can someone explain the value of 'this' in the above code please ?

My understanding:

this.value = value // Line 2 - here this refers to the global object elt.innerHTML = this.value; // line 4 - why is this 'possibly' undefined. Please explain.

Edit: btw I have thoroughly read the explanation for 'this' in this( How does the "this" keyword work? ) post ( from where I got the above code)

Community
  • 1
  • 1
gyaani_guy
  • 3,035
  • 7
  • 39
  • 48
  • `this` has nothing to do with closures or how the function was defined - it is only affected by how the function is invoked. – user2246674 Apr 30 '13 at 16:54
  • I see , but I just copied the line from the linked post – gyaani_guy Apr 30 '13 at 16:56
  • 2
    Should also read the linked post/answers then - the accepted answer contains a very thorough explanation. Then it just becomes an question of "Why is the ThisBinding not as I expect it to be?" - for that, go read the documentation for the method that *invokes* the callback. In this case, that would be [`.each()`](http://api.jquery.com/each/) – user2246674 Apr 30 '13 at 16:56

3 Answers3

3

Inside the function sent as callback to .each() method, this refers to the DOM element (for each one in this collection wrapped in jQuery object), not window:

More importantly, the callback is fired in the context of the current DOM element, so the keyword this refers to the element.

(BTW, that makes a bit redundant that elt arg; at least, it's a bit unclear why do you use both this and elt to refer to the same thing there).

Yet not all DOM Elements have value property defined: afair, it's set only for a subset of Elements: input, select, textarea, option etc. That's probably the reason why you get undefined as a result.

You can easily adjust this by using jQuery.proxy() method:

$('.some-elements').each($.proxy(function(elt){
    elt.innerHTML = this.value;
}, this));

Now the function sent into .each() uses the outer this as its context (obviously, it no longer points to DOM Element, as elt does).

raina77ow
  • 91,589
  • 12
  • 180
  • 210
  • 1
    Re "value property ... only for input and select", ` – Mike Samuel Apr 30 '13 at 17:19
1

In line 4, this.value is referring to the "each" instance of $('.some-elements'). Inside any function, it then refers to the object that the function is operating on. In the case of the anonymous function, it's the global scope.

krillgar
  • 11,554
  • 6
  • 43
  • 81
1

The basic algo that a JS interpreter uses to determine this is as below.

  1. When a function is called via its special call and apply methods, then this is the first parameter to call or apply.
  2. When a function is called from a bound function created via its bind method, then this is the this-value parameter to bind.
  3. When a function is called as a method (obj.method(params)) then this is the object from which the method is fetched, obj in the example.
  4. When a function is called otherwise, then this is the global object in non-strict mode or null otherwise.

Since each uses the special methods in (1) to pass the container as this, this in the inner function should be the result of $('.some-elements'), an array of jquery wrapped DOM nodes.

Mike Samuel
  • 109,453
  • 27
  • 204
  • 234
  • @Vlix, realized that just after I hit save. Please see my edit. – Mike Samuel Apr 30 '13 at 16:54
  • if each() wasn't using call/apply and instead was just calling the callback function like in `4` , then 'this' would have referred to the global object ? – gyaani_guy Apr 30 '13 at 17:02
  • @gyaani_guy, Since `each` is not defined in strict mode, yes. – Mike Samuel Apr 30 '13 at 17:16
  • There's also the `new` invocation. –  Apr 30 '13 at 17:29
  • @squint, Yeah. I was limiting myself to the builtin *[[Call]]* operator, not the *[[Construct]]* operator. *[[Construct]]* complicates `bind` since that's a source of common incompatibility with retrofitted `Function.prototype.bind` implementations. – Mike Samuel Apr 30 '13 at 17:30