0

I do not understand why the this value is the window object when I set the context for the f6 function to run with the object obj.

let obj = {
  color: "blue",
  name: "maya"
};

function f6() {
  return function() {
    console.log(this);
  }
}

f6.call(obj)();
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Bilal
  • 1
  • 1
  • 1
    The `this` in `function() { console.log(this); }` is distinct from the one in `f6` (and `this` isn’t used in the scope of `f6`). Use an arrow function instead: `function f6(){ return () => console.log(this); }`. – Sebastian Simon Jun 16 '21 at 00:43
  • Thank you. I understand that an arrow function would fix this issue. But I dont quite understand why the this in the return function would be different than the this in f6. Why is that? – Bilal Jun 16 '21 at 00:44
  • 1
    Every `function`, method, and `class` creates its own `this` binding scope. You’re not calling the returned function with any _this_ binding (you only do that with `f6`), so it’s `globalThis`. – Sebastian Simon Jun 16 '21 at 00:46
  • 1
    Related: [How does the “this” keyword work?](/q/3127429/4642212). – Sebastian Simon Jun 16 '21 at 00:57
  • 1
    Does this answer your question? [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Sven Eberth Jun 16 '21 at 01:18

1 Answers1

0

In function functions, this is not determined by lexical scope. It’s determined by how the function is called, and in what context. Each function function creates its own this binding environment.

function f(){
  this;          // This `this` is distinct …
  
  function g(){
    this;        // … from this `this`.
  }
}
function f(){
  console.log(this);
}

const objX = {
    f
  },
  objY = {};

objX.f();      // Logs `objX`, because the expression `objX.f` is a member of a reference.
f();           // No `this` binding. `f` by itself isn’t the member of a reference.
f.call(objY);  // Logs `objY`, because `this` was explicitly set.

Arrow functions, on the other hand, get the this binding from their lexical scope. Arrow functions do not create their own this binding environment.

function f(){
  this;          // This `this` is the same …
  
  () => {
    this;        // … as this `this`.
  };
}

You’re calling f6 with .call to provide a this binding. That’s where the f6 function gets its this value from, but f6 doesn’t use its this value.

Unrelatedly, f6 returns a function that happens to use this. Again, it’s a function function, so its this binding depends on the call. If you’re wondering what the returned function’s this value will be, you’ll have to examine the call:

f6.call(obj)();

// Equivalent to:
   (f6.call(obj)) ();
// -^^^^^^^^^^^^-      Returned function.
//                ^^   Call.

.call or .apply isn’t used on the returned function, and .bind wasn’t used, so the this binding isn’t set explicitly. (f6.call(obj)) also isn’t an expression with a member of a reference (i.e. a MemberExpression). The call was performed without providing a context, so the context will be globalThis, or undefined in strict mode.

Using an arrow function resolves this:

function f6(){
  return () => console.log(this);
}

f6.call(obj)(); // Logs `obj`.

Alternatively, using .bind in the return would also resolve this:

function f6(){
  return function(){
    console.log(this);
  }.bind(this);
}

f6.call(obj)(); // Logs `obj`.

And of course, using something that is lexically scoped1, i.e. variables, would also resolve this:

function f6(){
  const that = this;
  
  return function(){
    console.log(that);
  };
}

f6.call(obj)(); // Logs `obj`.

1: I guess you could say that this is also lexically scoped, but is overshadowed by each nested function function.


See also:

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
  • Thank you very much Sebastian. So it seems like the "this" isn't inherited by the parent function which I initially presumed. I forgot to consider how it was called. It was very helpful to see it like this: (f6.call(obj))() since this shows where I am calling it from which is just the "window" object: window.(f6.call(obj))(). Thanks again, Sebastian. – Bilal Jun 16 '21 at 03:35