Help making sense of this with arrow functions as methods

I thought this in arrow functions captures the enclosing context, in this case obj2. Can anyone tell me why it does not?

const obj = {
  key1 : "val1",
  method : function() { console.log(this.key1); }
console.log(obj.method()); // "val1"

const obj2 = {
  key2 : "val2",
  method : () => console.log(this.key2)
console.log(obj2.method()); // undefined

this specifically works differently in arrow functions than normal functions.

In short, with arrow functions there are no binding of this .

In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever.

With arrow functions the this keyword always represents the object that defined the arrow function.

1 Like

Thank you! Based on that definition, shouldn’t obj2 be represented by this inside the arrow function?

Arrow functions do not have their own ‘this’ binding so there is no way that you can refer to ‘key2’ since ‘this’ does not bind to the the obj2 object when using the arrow function.

Quiz: If ‘this’ is not binding to obj2 then what is it binding to?

1 Like

Ok, that makes sense. I learned from this next test that objects do not generate their own (bindable) context. You need an ES5 function. Otherwise (to answer your question) this binds to the global object or undefined in normal/strict mode.

const obj3 = {
  key2 : [1,2,3],
  method : this.key2.forEach(() => console.log(this)) // this is undefined here too

I have a followup question. The first log statement below suggests that objects do not create contexts. This is confirmed by the 2nd log statement that reiterates what has been said about arrow functions also not creating a context, and thus reaching outwards for one (global object here).

The 3rd log statement, however, does not show method outer as the context of this. It shows the entire object!

How can this be? Didn’t we disqualify obj as a context of its own from the prior two log statements?

const obj = {
  key1 : "val1"
  , internalRef : this.key1
  , arrowMethod : () => console.log(this)
  , outerFunc : function() {
      const innerArrowFunc = () => this;

//console.log(obj.internalRef); // undefined
//console.log(obj.arrowMethod()); // global object
console.log(obj.outerFunc()); // object literal showing  obj, in full, as its context

My best guess is that the method outerFunc converts obj into its context at runtime. And this context is detroyed after the method invocation completes. Is that correct?

The way you are defining outerFunc creates a closure:

The closure consists of the outer scope (or the ‘parent scope’) of the function. So outerFunc has access to all of the variables/methods in obj and ‘this’ points to the closure. That’s why you would be able to access this.key1 inside of outerFunc if you wanted to (and that’s why innerArrowFunction returns an object, because the object is outerFunc’s parent scope).

Yes, the closure is created at runtime when outerFunc is invoked.

1 Like