2

I have put together a small script as part of a larger quiz project and am struggling to understand why the this keyword is being set in the function before it is called. Here is my code:

$(document).ready(function ($) {

     function nextCard() {
         console.log('yes');
         $(this).closest('.card').hide();
         $(this).parent().next().show();
     }

    $("#start").on('click', function (e) {
        e.preventDefault();

        //First card to appear
        nextCard();
    });

    $("#next").on('click', function (e) {
        e.preventDefault();
        nextCard();
    });
});

Why would 'this' not be set to element #start for instance?

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
dreamkiller
  • 189
  • 3
  • 17
  • If you want `this` to be the element, you'd have to **reference** the function, as in `$("#next").on('click', nextCard)` – adeneo Jul 20 '17 at 15:24
  • See my answer in [**this post**](https://stackoverflow.com/questions/41496958/this-does-not-work-properly-in-another-event-im-clueless-as-to-why/41496969#41496969) for how `this` works. – Scott Marcus Jul 20 '17 at 15:29

2 Answers2

5

Within nextCard(), this will refer to the window as that's the default scope. Hence your DOM traversal methods most likely are not working as you expect them to.

Assuming you want this within the function to refer to the clicked #start or #next element, you could provide the reference of nextCard() to the event handler methods, like this:

$(function($) {
  function nextCard(e) {
    e.preventDefault();
    console.log('yes');
    $(this).closest('.card').hide();
    $(this).parent().next().show();
  }

  $("#start, #next").on('click', nextCard);
});
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
  • Thanks for this, but my intention is to add different functions within these two respective functions so can't have them within the same one – dreamkiller Jul 20 '17 at 15:32
  • In that case you could split them: `$('#start').click(startCard);`, `$('#next').click(nextCard);`. I simply joined them in the answer to make it more succinct. – Rory McCrossan Jul 20 '17 at 15:32
  • But my intention is to call the nextCard function within this click function and do other things. If I set the function to nextCard for both instead of function(e) {} then I won't be able to add anything further to these functions. – dreamkiller Jul 20 '17 at 15:35
  • In which case you'd need to use `call()` to maintain scope, as @Tomalak pointed out – Rory McCrossan Jul 20 '17 at 15:40
  • Thanks, did the job! – dreamkiller Jul 20 '17 at 15:54
4

Why would 'this' not be set to element #start for instance?

Why would it be? It's not that it can sense what you want it to do.

Use Function#call to define what object this should point to during the call. If you don't explicitly define it, this will default to the global object (Window in browsers).

$(document).ready(function ($) {

    function nextCard() {
        console.log('yes');
        $(this).closest('.card').hide();
        $(this).parent().next().show();
    }

    $("#start").on('click', function (e) {
        e.preventDefault();

        //First card to appear
        nextCard.call(this);
    });

    $("#next").on('click', function (e) {
        e.preventDefault();
        nextCard.call(this);
    });
});

Using someFunction.call(this); will effectively "transfer the current meaning" of this to the called function, or more technically, call someFunction in the context of whatever object this is referencing at the moment.

jQuery does something like the above automatically - it sets this for you to the proper DOM element when it calls event handlers. You can make use of the automatic this handling like @Rory McCrossan's answer shows – or you handle this yourself.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Thanks for this and explanation – dreamkiller Jul 20 '17 at 15:54
  • @dreamkiller It just so happens that I have written another take on the same subject today, read the lower part of https://stackoverflow.com/questions/45210122/why-cant-promise-resolve-be-called-as-a-function/45210249#45210249 if you're interested. – Tomalak Jul 20 '17 at 15:59