2

What I understand is that arrow functions don't rebind this, so why does it refer to different objects depending on how it's invoked?

const foo = {
  speak() {
    (() => {
      console.log(this);
    })();
  }
};

foo.speak(); // Logs foo

const speak = foo.speak;

speak(); // Logs the global object

Thank you for your time!

Osama Bodiaf
  • 99
  • 2
  • 6
  • From mdn. An arrow function does not have its own this. The this value of the enclosing lexical scope is used; So, in the first case you use the scope of the object because it has its own scope, the second time `const speak` is defined in the global window. Which means calling `speak()` will use the lexical scope of the global window. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions – Vladimir Bogomolov Jul 22 '20 at 13:29
  • Does this answer your question? [What does "this" refer to in arrow functions in ES6?](https://stackoverflow.com/questions/28371982/what-does-this-refer-to-in-arrow-functions-in-es6) – Heretic Monkey Jul 22 '20 at 13:34
  • ``this`` always looks at the object before it. Because it is not called the second time, the object before ``. `` is global – iopzhu Jul 22 '20 at 13:36
  • The arrow function is defined in the scope of the `speak` method, that's where it gets its `this` value from. – Bergi Jul 22 '20 at 14:12

3 Answers3

1

Arrow functions preserve the lexical value of this. What this means is, the value of this depends on how the arrow function is defined and not on how the arrow function is invoked.

The inconsistent behavior you see here is because the inner arrow function is being "defined" every time the function speak is being invoked. At that point of definition, the arrow function captures the current value of this which is different for foo.speak() and speak().

As a side note, this seems like JavaScript trivia. I wouldn't expect a "real" codebase to have this kind of snippets.

Shouvik Roy
  • 109
  • 5
1

The arrow function is being defined and executed only when and each time speak is called. The first time you call it is as a method on foo, therefore this is bound to foo. The second time you call it, this is the window. Compare to this version:

const foo = {
  speak: () => {
      console.log(this);
  }
};

foo.speak(); 

const speak = foo.speak;

speak(); 

Where the speak function is the arrow function and therefore the this is bound immediately to the window object for both calls.

James Thorpe
  • 31,411
  • 5
  • 72
  • 93
0

I believe what's happening is, when you assign the function to the const variable it loses it scoping.

When you call foo.speak(), the speak function is running in the context of foo, whereas when you run speak() after assigning the foo.speak function to the const variable, the function is running in the context of the global (window) object.

MDN states:

the value of this is determined by how a function is called (runtime binding). It can't be set by assignment during execution, and it may be different each time the function is called

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Phil Gibbins
  • 492
  • 5
  • 13