3

In my program using the function() syntax is returning the this value of a target element, but using an arrow function returns the window object. How are each of these two functions getting their this?

function editTemplates() {

//sits within for loop

    clocksTemplate.gmt[i].addEventListener('keydown', (e) => {
      console.log(this); //returns window object
    });

    clocksTemplate.gmt[i].addEventListener('keydown', function(e) {
      console.log(this); //returns element bound to clocksTemplate.gmt
    });

According to MDN with arrow functions, this should "retain the original meaning from the enclosing context". Is the enclosing context the event listener? or the function it sits within? According to my test, the enclosing context for the arrow function must be the Window object but I can't see how. With the function() syntax the enclosing function is meant to redefine the this value, which I'm assuming it is doing here within the addEventListener method. This topic has been discussed in depth here and here but I'm a JS newbie and I couldn't understand how this applied to my problem.

Community
  • 1
  • 1
kidconcept
  • 509
  • 6
  • 13
  • Arrow functions will bind `this` of current scope, while `addEventListener` will bind element as `this` – Rajesh Jan 17 '17 at 06:12
  • now the documentation is up to date and explicity says that can not be used for coding methods... https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#cannot_be_used_as_methods – Victor Feb 28 '23 at 19:03

1 Answers1

5

That is perfectly normal & expected behaviour of arrow functions.

As the documentation mentions about regular functions:

every new function defined its own this value (a new object in the case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.).

If it is required to override the value of this in a regular function, then instead of calling it directly, we can invoke it using call() or apply().

So in your case of regular function, the callback function is getting invoked internally by addEventListener function using a call() or apply() with value of this set to element bound to clocksTemplate.gmt. It's a standard practice to use call() or apply() for invoking callbacks.

In case of the first function (arrow function), the this does not get assigned any new value. They can't be invoked using call() or apply() because arrow functions are anonymous. So it continues to have the value that was defined by the enclosing function editTemplates() and that happens to be window.

See below for code example:

// REGULAR FUNCTION

function editTemplates() {

    console.log(this)    // window
    var myVar = this;

    // sits within for loop

    clocksTemplate.gmt[i].addEventListener('keydown', function(e) {

        // new value assigned for 'this' as element bound to clocksTemplate.gmt

        console.log(this);    // returns element bound to clocksTemplate.gmt

        console.log(myVar);    // returns window
    });



// ARROW FUNCTION (Anonymous Functions)

function editTemplates() {

    console.log(this)    // returns window object
    var myVar = this;

    // sits within for loop

    clocksTemplate.gmt[i].addEventListener('keydown', (e) => {

        // No new value gets assigned to 'this'

        console.log(this); // returns window object

        console.log(myVar);    // returns window object

        // Saves the hassle of saving 'this' to another variable!
    });

Hope this answers your question.

Santanu Biswas
  • 4,699
  • 2
  • 22
  • 21
  • You helped me understand how this is working, thanks! To anybody else mulling over the this problem, another way to get at the target of the event is to use the event.target method. In the above example it looks like this: clocksTemplate.gmt[i].addEventListener('keydown', function(e) { console.log(e.target); }); This isn't the answer to my question, but just a bit more info for future people reading this question – kidconcept Jan 17 '17 at 08:36
  • Am glad I could help. Please accept/upvote the answer if satisfied. – Santanu Biswas Jan 17 '17 at 08:38