0

As scope of this becomes available in ES6 arrow functions.

but here is a case in which I am unable to access this in the arrow function while it is working with normal anonymous function

Example

Sample 1

$(document).ready(function() {
    $('.principal').click(() => {
        alert($(this).parent().html()); // 'this' is undefined here
    });
})

Sample 2

$(document).ready(function() {
    $('.principal').click(function() {
        alert($(this).parent().html()); // 'this' is available here
    });
})
Vivek Maru
  • 8,347
  • 1
  • 24
  • 34

4 Answers4

1

In the first case

$(document).ready(function() {
    $('.principal').click(() => {
        alert($(this).parent().html()); // 'this' is undefined here
    });
})

Since you are using arrow function, the this object here will belong to the context Outer function which is the $(document).ready and it is thus to the entire DOM element as you can see in the below snippet and not the clicked element.

In the second case

$(document).ready(function() {
    $('.principal').click(function() {
        alert($(this).parent().html()); // 'this' is available here
    });
})

this refers to the context of the click function and thus it returns DOM element which is clicked

$(document).ready(function() {
        $('.principal').click(() => {
            console.log(this); 
        });
    })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="principal">Click</button>
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
1

The reason is that jQuery explicitly binds the this object in your click handler to the element on which the event was captured. The only way to get that context is by using a standard function, since indeed an arrow function ignores this binding.

So you need to either:

  • stick with a standard function for the callback, or
  • Use the currentTarget property of the event object argument that jQuery passes to the callback

The latter would look like so:

$(document).ready(function() {
    $('.principal').click((e) => {
        console.log($(e.currentTarget).parent().html());
    });
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div><button class="principal">Click me</button></div>

Outputs:

<button class="principal">Click me</button>
trincot
  • 317,000
  • 35
  • 244
  • 286
  • _"binds the context"_ should be "binds `this`". – a better oliver Apr 06 '17 at 10:43
  • Is that really so, JQuery doesn't work with arrow functions the way you'd typically expect? Very curious to see some detail on that somewhere, would like to run some tests to understand it fully. – Tim Consolazio Apr 06 '17 at 10:53
  • @TimConsolazio, jQuery will bind the `this` object to the callback, but arrow functions are by design immune to that -- which is nothing jQuery can influence. You can read about the arrow function's behaviour in this respect on [MDN "No binding of this"](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_binding_of_this), in [this blog](https://derickbailey.com/2015/09/28/do-es6-arrow-functions-really-solve-this-in-javascript/) and ["Can you bind arrow functions?"](http://stackoverflow.com/questions/33308121/can-you-bind-arrow-functions). – trincot Apr 06 '17 at 11:11
  • I understand arrow functions, I've been using them for quite some time. I misunderstood what you were getting at, but see now that your intent was to bind to the calling object; I typically avoid doing that in favor of binding to the closure that contains the handler, which is why typically I would prefer arrow functions. If however you were choosing to bind to the calling object, then I can see why you might not get the intended result from my answer. – Tim Consolazio Apr 06 '17 at 12:50
  • @TimConsolazio, from the Asker's code it looked like they wanted to have the jQuery behaviour, where `this` is set to the element that was selected with the jQuery selector. In that respect it makes little sense to try to set `this` already to that element before calling the `click` method on the $ selector. Another hint is that `$(document).ready` is typically called outside of any function, but at the top level of a script. Putting it in any other place is unnatural. – trincot Apr 06 '17 at 13:24
0

Change the outer function to an arrow function too.

$( document ).ready ( ( ) => {
    $( '.principal' ).click ( ( ) => {
        alert ( $( this ).parent().html() ); 
    } );
} );

You can also try (added this option based on comment):

$( document ).ready ( function {
    $( '.principal' ).click ( ( ) => {
        alert ( $( this ).parent().html() ); 
    } );
}.bind ( this ) );
Tim Consolazio
  • 4,802
  • 2
  • 19
  • 28
  • It is still `undefined` – Vivek Maru Apr 06 '17 at 09:45
  • Hmm I just tried it in a little naive example. I see a definition (albeit I am not using jquery). I have another option, I'll post as part of the answer. – Tim Consolazio Apr 06 '17 at 09:45
  • plus 1 for using bind – Vinod Louis Apr 06 '17 at 09:50
  • Yeah it's not ES6 pure but the explicitness of "bind" to me was always useful. – Tim Consolazio Apr 06 '17 at 09:52
  • You can't bind to arrow function. Please check this SO for more details: http://stackoverflow.com/questions/33308121/can-you-bind-arrow-functions – Bartek Fryzowicz Apr 06 '17 at 09:54
  • But what is `this` in this solution? Certainly not the `.principal` element, and so the `.parent()` method will fail. – trincot Apr 06 '17 at 10:14
  • Bartek, that was a typo, I just put the bind in the wrong place (notice I did change back to the "function", I just hadn't had my coffee yet). Thanks for pointing it out. – Tim Consolazio Apr 06 '17 at 10:45
  • Trincot, I wouldn't expect it to be the parent element. If you wanted access to that I think you'd be better off passing it in from the calling event. My assumption here is that "this" would be the object containing the handler. – Tim Consolazio Apr 06 '17 at 10:49
  • `$(document).ready` is hardly ever called from within an object, but typically from the top level of a script. Also, the object desired to have as `this` is being *selected* with the jQuery selector (`.principal`), so it is only there that it becomes known. – trincot Apr 06 '17 at 13:29
  • I understand that as well...? – Tim Consolazio Apr 06 '17 at 17:32
0

In arrow function this has its original meaning from the enclosing context. In the first example this inside ready callback points to document and as a result this inside arrow function passed as click handler also points to document.
In the second example with normal function as click handler this is internally binded by jQuery to the element on which click method was called. Arrow function doesn't bind this argument but uses enclosing context - that's why this can't be binded as in cacse of normal function.

In your examples you don't need to access outer context inside click handler so you shouldn't use arrow function in such case, use normal function.

Bartek Fryzowicz
  • 6,464
  • 18
  • 27