Everyone's Favorite Topic: Arrow Functions!

Here is my code:

"use strict";

const todoList = {
    todos: ['test', 'test2', 'test3'],
    //Is this code good enough? Can I pass "this" to an arrow function somehow? 
    //Should a method use arrow functions?
    displayTodos: function () {
        this.todos.forEach(element => console.log(element));
    },
    //Arrow function in strict mode "this" does not work, must use todoList
    displayTodos2: () => todoList.todos.forEach(element => console.log(element))
};

The comments explain what I am essentially working with here. For reference, I’m very new to JS, and completely new to ES6, and arrow functions and “this” are kind of insane to me. With some research and tinkering, I managed to turn displayTodos into displayTodos2 which uses two arrow functions.

  • Aside from the fact that if I did not write this, it would melt my brain trying to understand it, which method is correct for best practices?
  • Am I missing a parameter that lets me use “this” on displayTodos2?
  • Is this garbage code that is unreadable for other humans?

It seems like when you’re using “this” on the 2nd method, “this” is actually the global object. It’s like if you wrote a function outside of an object and used “this”, that would access the global Object. Inside of the first method, “this” is giving access to the owner object, which is todoList. I personally don’t know why that is but that’s interesting.

I hope someone else can be more helpful than me on this. I usually only use arrow functions as callback functions (like inside of map, filter, forEach, etc).

1 Like

Your explanation helped me to understand this a bit more, and I remembered seeing this in the MDN Arrow functions used as methods.

For whatever reason, using an arrow function as a method does not create what you called an “owner object” for this to attach to, so it attaches to the global object. It is interesting that the arrow function inside of this arrow function attaches to the owner object however! From my interpretation here, arrow functions attach to the “second-most” parent object, which for the inner arrow function is the object, and the method arrow function is global.

As stated previously, arrow function expressions are best suited for non-method functions. Let’s see what happens when we try to use them as methods:

'use strict';

var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log(this.i, this);
  }
}

obj.b(); // prints undefined, Window {...} (or the global object)
obj.c(); // prints 10, Object {...}

Arrow functions do not have their own this .

This is just speculation but maybe arrow functions are a different type of object than functions classified with function. Like functions classified with function are equipped with the properties to become a method and use “this” in the way you want to use it. While arrow functions are not equipped with that ability. I find objects in javascript to be difficult to learn about and understand.

I believe I have found my answer, and it looks like arrow functions SHOULD NOT!!! be used as a method. Functions can be added to an object as a method for specific reasons. This article explains the difference between method functions and method arrow functions.

Functions work well as method implementations: They have a special variable called this that refers to the object via which the method has been invoked. In contrast to other free variables, this isn’t looked up in the surrounding lexical scopes, it is handed to the function via the invocation. As the function receives this dynamically, it is called dynamic this .

To understand this, we have to understand that:

lexical scopes are the syntactic constructs that surround it (a trait of the source code or the lexicon ).

Also:

Its dynamic scopes are the function that called it, the function that called that function, etc. Note the nesting that occurs in both cases.

From Stack Overflow on what is lexical scope:

Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned .

Here’s my translation in plain English.

When you write a function as a method, it creates a dynamic scope, so it no longer needs to look to the parent element for what this should refer to. When you use a function to create a method, that function dynamically says "hey, ignore the usual structure (lexical) and refer to me if you want to use this.

When we use an arrow function to create a method, it doesn’t come with this automatic behavior and use the usual structure (lexical) to lazily say "eh, whatever my parent element says this should be, go ahead and refer to it instead of me. It seems that arrow functions are designed to intentionally use lexical instead of dynamic scope, which brings me to the final point. A quote from the original article:

Functions don’t work well as implementations of subroutines, because this is still dynamic. The subroutine call sets it to undefined in strict mode [1] and to the global object, otherwise. That is unfortunate, because the subroutine has no use for its own this, but it shadows the this of the surrounding method, making it inaccessible.

When he says subroutines, he means callback functions like map() and filter() that you mentioned earlier.

This is super cool! The same reason that functions should be used for methods is the same reason they suck as callback functions. A callback function never(?) has a reason to refer to itself with this since its only goal is to perform an action and return it so that the value can be modified by the higher-order function like map() or filter(). Functions screw this up by doing their dynamic look at me action.

Meanwhile, arrow functions are perfect! An arrow function grabs the callback function, returns the value, and gets out of the way (lexical) so that this can refer to the scope of the parent function this, which is the object!

Edit: Another note that shows how this works, is that using .forEach on an array allows for an argument this after you write the callback function argument, so that this can be assigned to whatever you want instead of being lexical and going to global or undefined.

thisArg Optional

Value to use as this when executing callback .

Edit: Not sure if it’s bad manners to mark my own response as the answer, but unless anyone has corrections to make I believe this is the correct answer for anyone looking at this in the future!

1 Like