0

My goal is that I'm trying to pass the this context from a normal function to an arrow function but I keep getting undefined.

I know that this in a normal function behaves dynamically and determined by how the function was called. The this inside an arrow function follows lexical scoping rules to determine its value. However, when I call printWrapper() on line 16, this is set to the car object, so when I further call printThis(), as per the lexical scoping rules, it should print the car object, but in my case the this object being printed on line 2 is the global object.

printThis = () => {
  console.log(this); // prints the global object
}

var car = {
  year: 2015,
  printThis: printThis,
  printWrapper: printWrapper
}

function printWrapper() {
  console.log(this); // prints the car object
  printThis();
}

car.printWrapper();
Frosty
  • 15
  • 8
  • 3
    Lexical scoping works with respect to the static structure of the source code. – Pointy Sep 03 '19 at 20:55
  • 1
    Possible duplicate of [Are 'Arrow Functions' and 'Functions' equivalent / exchangeable?](https://stackoverflow.com/questions/34361379/are-arrow-functions-and-functions-equivalent-exchangeable) . Note that the crucial thing is the lexical structure of the function *definition* not the function *invocation* (which would be dynamic scoping). – John Coleman Sep 03 '19 at 20:58
  • MDN explains it pretty well https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions – epascarello Sep 03 '19 at 20:58
  • lexical scoping means that it inherits the value of `this` from the scope where the function was defined, not where it's called. – Barmar Sep 03 '19 at 21:07
  • And since the function is defined in the global scope, it gets the global `this`. – Barmar Sep 03 '19 at 21:09
  • When you use arrow functions it no more holds the reference of the place from where it is called. Here the scope of arrow function is global, hence you will get the global object – Milind Agrawal Sep 03 '19 at 21:17
  • @Pointy I think I might've confused lexical and dynamic scoping. I guess moving the arrow function inside printWrapper() and then calling it there will print me the car object. – Frosty Sep 04 '19 at 07:07
  • @JohnColeman not a duplicate as I know how arrow functions and normal functions work. I mixed them up when using it together. – Frosty Sep 04 '19 at 07:12
  • @Frosty That question has become the goto duplicate target for anyone confused about `this` and arrow functions (in much the same way that "Is floating point math broken?" has become the standard dup target for many floating-point questions). A duplicate target doesn't have to be exact to be useful. – John Coleman Sep 04 '19 at 13:23

2 Answers2

0

As said in the comments, the context of an arrow function is the same context of the scope where it was defined, not the context from where it is called.

If you need to "pass the this context" to a function you could use Function.prototype.bind(), it will return a new function with the first passed argument assigned to this. Function.prototype.call() or Function.prototype.apply() works similarly by calling the function in place with the desired this.

Please note that this methods will work only with normal functions. Arrow functions are anonymous and their context cannot be explicitly set.

function printThis() {
  console.log(this); // prints the car object
}

var car = {
  year: 2015,
  printThis: printThis,
  printWrapper: printWrapper
}

function printWrapper() {
  console.log(this); // prints the car object
  printThis.call(this);
}

car.printWrapper();
Ernesto Stifano
  • 3,027
  • 1
  • 10
  • 20
  • I'm aware of and have used bind(), but my goal here was to try to pass the *this* of printWrapper() to an arrow function which is printThis(). – Frosty Sep 04 '19 at 07:15
0

So I mixed up lexical and dynamic scoping and assumed that printThis() will be able to access the this of printWrapper(). As Pointy mentioned that lexical scoping works with respect to the static structure of the code which means that moving the printThis() function inside printWrapper() will allow its own this to be accessible from printThis().

var car = {
  year: 2015,
  printWrapper: printWrapper
}

function printWrapper() {
  console.log(this); // prints the car object
  printThis = () => {
    console.log(this); // also prints the car object, *this* now refers to the scope of printwrapper
  }
  printThis();
}

car.printWrapper();
Frosty
  • 15
  • 8