0
function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // this refers to the person object
  }, 1000);
}

But what if I want to access the "this" of the setInterval function, instead of the parent object. I know arrow functions don't have a lexical this of their own, but is there a way to circumvent this, other than writing a non-arrow function?

hashedram
  • 813
  • 7
  • 14
  • 2
    Think carefully, what is `this` of `setInterval` function, and put the answer to a comment below ... – Teemu Feb 26 '18 at 11:59
  • @Teemu what will be the `this` of `setInterval` – zabusa Feb 26 '18 at 12:00
  • @zabusa Waiting for hashris' answer ... – Teemu Feb 26 '18 at 12:01
  • @Teemu In case of arrow functions, this refers to the scope of Person. In case of ES5 functions, this would refer to the scope of the setInterval function itself, not its parent. I want to know if an ES6 function can somehow have its own scope. – hashedram Feb 26 '18 at 12:04
  • @hashris Yes, an ES6 `function` can… – Bergi Feb 26 '18 at 12:05
  • @Bergi how so, doesn't it take the lexical scope of its parent? – hashedram Feb 26 '18 at 12:06
  • 2
    You're now mixing scope and execution context. In a "traditional" function expression `this` would refer to `window`, or in the strict mode it would be `undefined`. – Teemu Feb 26 '18 at 12:06
  • Trying to circumvent the nature of an arrow function to do what does a function, is just wrong. You have function and arrow function choose your pick and use it as you need. – juan garcia Feb 26 '18 at 12:17
  • 1
    AFAIK you can think of `() => {}` as `(function(){}).bind(this)`. Which hopefully explains why you can't change `this`. No matter what you do it has already been bound. It's like it made a new function that calls the original function with whatever `this` was at bind time. In fact you could implement `bind` something like `function bind(fn, context) { return function() { return fn.apply(context, arguments); }; }` in which you can see bind is making a closure that calls `fn` with `context`. That function is closed. You can't change `context` after calling `bind`. – gman Feb 26 '18 at 12:29
  • 1
    *"I know arrow functions don't have a lexical this of their own"* It's exactly the other way round. Arrow functions are the only functions with "lexical `this`" , i.e. `this` is resolved lexically vs dynamically. https://www.ecma-international.org/ecma-262/8.0/#sec-function-environment-records – Felix Kling Feb 27 '18 at 05:05

3 Answers3

5

Is there a way to circumvent this, other than writing a non-arrow function?

No.

The this value that is passed into an arrow function is ignored by it and not available in any form.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Could you explain why? – Pau Feb 26 '18 at 12:05
  • 1
    @Pau You mean why it is ignored? Because it's designed to. It doesn't have its own `this` that the value could be set for, precisely so that when you use the `this` keyword in the arrow function body it refers to the one of the parent scope. – Bergi Feb 26 '18 at 12:09
  • I meant if there was something related to scope, anyway thanks! – Pau Feb 26 '18 at 12:11
4

No, the arrow function does not possess athis variable (nor argument, super & new.target) so there is nothing to "circumvent" to.

An arrow function is designed to inherit lexical scope, if it did have its own this- it would interfere with its defining behavior.

Don't think about arrow functions as a nice shorthand for a regular function.

Instead, you should "read" arrow functions as:

...execute these statements in the surrounding context...

and

...this function does not have the mental overhead of tracking which, of the 4 patterns of invocation, are being used to determine the value ofthis)

Ashley Coolman
  • 11,095
  • 5
  • 59
  • 81
1

The this of setInterval() = window.
If you have strict mode enabled in your script (something like 'use strict'; at the start of your script) it will be undefined. For all intents and purposes you might wish to use the global scope of window

You can rewrite your function to access window like this:

setInterval(() => {
    this.age++; // this refers to the person object
    window.something = this.age;
}, 1000);

Also, you're not saving the setInterval ID so you can't clear it when the object is obsolete. It will remain in memory causing you potential memory leaks

function Person(){
  this.age = 0;
  this.kill = function() {window.clearInterval(this.interval);};
  this.interval = setInterval(() => {
    this.age++; // this refers to the person object
  }, 1000);
}

So that when a Person is obsolete, you can kill() them, leaving no traces of them.

Tschallacka
  • 27,901
  • 14
  • 88
  • 133