Why "This" Is Undefined Inside a Fat Arrow Function Definition

Why this is undefined inside a fat arrow function definition?

Unlike regular functions, Arrow functions does not have a this of their own, only regular functions and global scope have this of their own.

Which would mean that whenever this would be referred in arrow function, it will start looking up the scope to find the value of this, or in this case, during lookup it found, that the object is not having a this of its own, hence, it went up to global scope and bound the value of this with global scope, where it won't find anything. These two examples will solve your doubt.

var obj = {
a : 'object???',
foo : () => { console.log(this.a) }
};

var a = 'global!!!';

obj.foo(); // global!!!

Wrapping arrow within a function

var obj = {
a : 'object???',
foo : function() {
return (() => {
console.log(this.a)
})();
}
};

var a = 'global!!!';

obj.foo();

Here, I have tried to explain the behaviour of this for arrow in depth.

https://github.com/anirudh-modi/JS-essentials/blob/master/ES2015/Functions/Arrow%20functions.md#how-this-is-different-for-arrow-functions

This undefined in fat arrow function but is defined in the enclosing scope

You have three different arrow functions and none of them attempts to use this.

I actually do not need this in any of the arrow functions, but upon debugging I found that this is undefined in their scope for some reason.

This is a performance optimisation.

If a variable isn't used in a function then it will not exist in that function, even if it would otherwise be in scope.

This allows, for example:

function foo () {
var bar = something_that_returns_a_memory_intensive_object()
return () => console.log(1);
}

const baz = foo();

After foo has finished running and returns its function, bar (and the large object) can be garbage collected.

The same is true of this.

I now added a console log in the arrow function and apparently it is defined!

… and when you use it, the variable is closed over and made available.

Why in Fat arrow functions arguments object is undefined

According to MDN

An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

Why does 'this' return 'undefined' when referred in an arrow function but doesn't when called on an anonymous function?

Because arrow functions don't have their own this, they close over the this of the calling context. But non-arrow functions, if they're not bound, take this based on how they're called. I assume you're calling these functions like this:

obj.getScopeWithArrow();
obj.getScopeWithAnonymous();

In the first case, again, the arrow function doesn't get its own this so it doesn't matter how you're calling it. In the second case, it does matter, and calling it like that makes this within the call refer to the same object obj refers to.


Separately: In your example, you must be in strict mode, because this can only be undefined in strict mode.

Separately 2: With regard to your method names: this and "scope" have very, very little to do with one another.


Some examples:

function showThis(label, t) {  if (t === window) {    console.log(label, "(global object)");  } else {    console.log(label, t);  }}// Loose mode by default in a non-module script elementlet obj = {  arrow: () => {    showThis("arrow says ", this);  },  normal: function() {    showThis("normal says ", this);  }};obj.arrow();  // global object (window on browsers)obj.normal(); // obj
function foo() { // Here, we're in strict mode "use strict"; let obj = { arrow: () => { showThis("arrow says ", this); }, normal: function() { showThis("normal says ", this); } }; obj.arrow(); // undefined obj.normal(); // obj
}foo();

Arrow function is undefined when passed as props

Non-arrow functions are still hoisted in classes. If you move bananaEvents after defining the arrow functions your class will work normally.

I tested this just now with

class Test {
vars = { one: this.firstFunction(), two: this.secondFunction() }
firstFunction() { return 1
}
secondFunction = () => 2
}
const test1 = new Test(); // will give an error function undefined

and

class Test2 {
firstFunction() { return 1
}
secondFunction = () => 2

vars = { one: this.firstFunction(), two: this.secondFunction() }
}
const test2 = new Test2(); // works normally

Vue: Access component object inside methods

According to official docs You should use normal function instead of arrow one in order to get access to the component instance :

    methods: {
getInput() {
return this.$ref.input.value
}
}

Note that you should not use an arrow function to define a method (e.g. plus: () => this.a++). The reason is arrow functions bind the parent context, so this will not be the Vue instance as you expect and this.a will be undefined.

Why React Function Component's this is undefined

Function components can be written using both arrow functions () => {} like shown in the above question, or as regular function expressions/declarations such as function Foo() {}. To understand why the above behavior occurs, it is important to first understand that React components are (often) written within ES6 modules.

Why is this undefined in an arrow function component?

One of the properties of modules is that this at the top "module scope" level is undefined. This behavior differs from regular scripts:

<!-- A "module" is what react component code is usually written in -->
<script type="module">
console.log("Module code (react code) this:", this); // undefined
// ^
const App = () => { // example component |
this // --- taken from surrounding scope ---+
}
</script>

Fat arrow or function() with this keyword

Use the traditional function declaration, because it will decouple your handleUpdate() function from the UI, so:

  • you can implement it in a totally different file and reuse it wherever you need its functionality
  • the function does not need to have an input variable defined in the context where it's used

If you're still doubting that's the way to go, VueJS also uses traditional functions in several places, having stuff that's actually not working if fat arrow functions were used:

From Vue's official docs:

Don’t use arrow functions on an options property or callback, such as created: () => console.log(this.a) [...]. Since arrow functions are bound to the parent context, this will not be the Vue instance as you’d expect, often resulting in errors such as Uncaught TypeError: Cannot read property of undefined.

So yeah, don't worry about using traditional functions, especially if you can explain the why's behind your choice.



Related Topics



Leave a reply



Submit