0

I figured this doubt out while typing the question, but I think it still makes sense to have this documented for future devs.

Looking for help with understanding outputs of following: (primarily case 4 vs case 5)

var obj1 = {
  x:1,
  getX: function () {
    const inner = () => {
      console.log('1:',this.x);
    }
    inner();
  }
}
obj1.getX();

var obj2 = {
  x:1,
  getX() {
    const inner = () => {
      console.log('2:',this.x);
    }
    inner();
  }
}
obj2.getX();

var obj3 = {
  x:1,
  getX: () => {
    const inner = () => {
      console.log('3:',this.x);
    }
    inner();
  }
}
obj3.getX();

function a() {
  this.x = 1;
  function b() {
    console.log('4: ', this.x);
  }
  b();
}
a();

var obj5 = {
  x: 1,
  getX() {
    const inner = function() {
      console.log('5: ',this.x);
    }
    inner();
  }
}
obj5.getX();

SPOILER ALERT!!! BELOW THIS LINE ARE MY GUESSES AND EXPLANATIONS!!! Best to try these out on your own before reading further.

My understandings:

Case 1: Since inner is an arrow function, this of parent is considered. Hence 1 makes sense.

Case 2: Semantically, I don't see any difference between Case 1 and Case 2. Please correct me if I am wrong here.

That is, {getX(){}} vs {getX: function(){}} should be equivalent.

Case 3: Since both inner and getX are arrow functions, this represents that of window scope and hence accordingly the output should be undefined.

Case 4: Since call to inner function does not have object associated, it's this refers to parent method's this which implies same as that of a. Hence, output is 1.

Case 5: Since call to inner function does not have object associated, it's this refers to parent method's this which implies same as obj4obj5. Hence output should be 1.

NOTE: Case 5 output is undefined. Need help understanding this.

NOTE 2: In console of new browser tab, copy paste only Case 5. You will see undefined. While if you copy paste all of these cases together, output for Case 5 will be 1.

  • 3
    "*Case 4: Since call to inner function does not have object associated, it's this refers to parent method's this*" - no. The [value of `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is determined by the call `b()` or `a()`, which don't pass any context, and defaults to the global object therefore (use strict mode!). – Bergi Mar 23 '21 at 00:48
  • Does this answer your question? [Arrow Functions and This](https://stackoverflow.com/questions/28798330/arrow-functions-and-this) – Nick Mar 23 '21 at 00:54
  • A Q&A about Case 3: [Arrow Function in Object Literal](https://stackoverflow.com/q/36717376/4642212). – Sebastian Simon Mar 23 '21 at 01:28
  • Related: [How does the “this” keyword work?](https://stackoverflow.com/q/3127429/4642212). – Sebastian Simon Mar 23 '21 at 01:39
  • @SebastianSimon - thanks for your comment. I tried again different scenarios on both Chrome and Safari and then added Note 2 in my original post. – Vaibhav Agarwal Mar 24 '21 at 03:41

2 Answers2

1

You might just print out this instead of this.x, it’d be easier to understand. Case 1-3 this refers to obj_n, while case 4 and 5 it refers to window global object.

this context, for non-arrow normal function() {}, is not bound at declaration. It is not determined until when the function is called. And when function is called it is kind of a requirement to explicitly specify what this should be, by using one of:

  1. contextObject.methodName() syntax, if available
  2. functionName.call(context) or functionName.apply(context)

If such specification is not provided, then in sloppy mode js, this would fallback to be the window global object, in strict mode js, it would be undefined.

It does not “refers to parent method's this”.

hackape
  • 11,966
  • 1
  • 15
  • 40
  • 1
    Would it be accurate to say that `inner();` (inside `getX` in case 5) is called _without context_ and that’s the reason why the `this` inside the `const inner` function is `window` (or `globalThis`, or `undefined` in strict mode)? The `this` is solely taken from context binding, not from call scope, right? E.g. if there was a fictitious `magicObject` and the call was actually `magicObject.inner();`, then `this` in that function would’ve referred to `magicObject`, just as it would with `inner.call(magicObject)`, correct? – Sebastian Simon Mar 23 '21 at 01:52
  • 1
    To expand on the second paragraph a bit: it’s not enough for a function to be a property of something, e.g. `const obj = { x: 1, getX: function(){ return this.x; } }, myGetX = obj.getX; myGetX();` results in `undefined` because `myGetX();` is a call without a binding context. The `obj` [context got lost](/q/30486345/4642212) at the variable assignment `myGetX = obj.getX`, although you may assume that `obj` somehow “sticks” to `getX` because it’s been defined inside of it — but no: `getX` is simply a regular function that has no knowledge of `obj`, unless it gets called with it as context. – Sebastian Simon Mar 23 '21 at 02:01
  • @SebastianSimon Yes, your understanding is totally correct! – hackape Mar 23 '21 at 03:17
-2

Reason: In case 5, because inner method is not associated with any object when called, it's this refers to parent method's this. Here, parent method's this implies this of the method where all of the code is encapsulated in. Quite an interesting, I would say, "glitch".

To understand it better:

function main() {
  this.x = 15;
  var obj5 = {
    x: 1,
    getX() {
      const inner = function() {
        console.log('5: ',this.x);
      }
      inner();
    }
  }
  obj5.getX();
}
main();

prints: 5: 15

  • 1
    You might just print out `this` instead of `this.x`, it’d be easier to understand. Case 1-3 `this` refers to `obj_n`, while case 4 and 5 it refers to `window` global object. It **does not** “refers to parent method's `this`”. – hackape Mar 23 '21 at 01:27
  • 1
    1. This is not a "glitch", it's how the `this` keyword works 2. your explanation is misleading - there is no direct tlink between the `this` when calling `inner` and the `this` of `main`. It just happens that both are `window` because neither will have `this` set to anything and the code is not running in strict mode. See [How to access the correct `this` inside a callback?](https://stackoverflow.com/q/20279484) – VLAZ Mar 23 '21 at 05:58