Gamify! - A Gamified Approach to Named vs Arrow Functions
Tags: learning, javascript, gamification, tutorial
Published: 2020-08-21 03:09:12

## Background

This is one part in a series called **Gamify!** where I try to create Gamified versions of the typical tutorial. I try to gamify learning since I believe its the best way for all skill and passion levels to get what they want out of the tutorial as well as been fun and informative. When going through this tutorial, there is a **level** that corresponds to how much and how in-depth you want to learn about the topic. If you just want to know what the topic is about **Level 0** should be enough, but if you care about the nitty gritty details, **Level 4** might be of interest.

## Table of Contents

|Levels|
|:-----|
|[Level 0 :joystick:](#Level-0)|
|[Level 1 :game_die:](#Level-1)|
|[Level 2 :black_joker:](#Level-2)|
|[Level 3 :video_game:](#Level-3)|
|[Level 4 :dart:](#Level-4)|

## Introduction

Within Javascript you have probably seen something like: 
```javascript
const fun = () => {
    // statements...
}
```

When encountering this syntax for the first time, it can really confuse you (it did for me) and it took me a while to get used to what it mean and why it was used. 

---

Well fret no further because I am going to demystify this for you!

## Level 0

### What are "Arrow Functions"?

Arrow functions are another syntactical method to declare functions in Javacript (and Typescript). Basically its another form of function declarations with the following syntax:

```javascript
(param1, param2, param3, ..., paramN) => { statements }
```

However with arrow functions, they must be assigned to a variable.

Here is an example: 

```javascript
// Declaration
const func = (a) => {
    return a * a;
}

// invocation
func(10) // returns 100
```

This as opposed to the regular function declaration:

```javascript
// Declaration
function namedFunction(a) {
    return a*a;
}

// Invocation
namedFunction(10) // returns 100
```

Notice how the two functions had the exact same result with the same input! Basically, whenever you encounter this syntax, just read it as a regular function in your head!

If you want to learn more, progress to the next level!

---

<img style="margin-left: auto; margin-right: auto; display: block" src="https://dev-to-uploads.s3.amazonaws.com/i/oyx68dvyhjfm95ytskf8.png" alt="drawing" width="150"/>

## Level 1

## Differences between Named vs Arrow Functions

Out of all the differences, there is one really important difference between Named and Arrow functions:

### "This" context

Arrow functions do not redefine the context of the `this` keyword when created. This is different from that of named functions which do redefine the `this` context based on what scope it is in.

Back when I first encountered arrow functions and read about their differences, I still didn't understand what the difference was. To help you avoid frustration and understand better, I have created a quick analogy:

Think of **Named functions** (ie. when using "function" keyword) as **Mario** and *Arrow functions* (ie. "() =>" syntax) as *Luigi*. **Named functions** and *Arrow functions* have the same end goal: defining a function similar to how **Mario** and *Luigi* have the same end goal of defeating Bowser and saving Princess Peach. However, **Mario's** fireball ability and *Luigi's* fireball ability differ in that **Mario's** fireball adheres to the rules of gravity while *Luigi's* fireball does not and is independent of the rules of gravity. **Named functions** and *Arrow functions* have a similar pattern. **Named functions** always follow the rule of defining the "this" context to its outer scope, while *Arrow functions* do not follow this rule. Basically, **Named functions** similar to **Mario's** fireballs follow rules while *Arrow functions* and *Luigi's* fireballs do not follow the rules, even though the overall goals for both are the same.

### How "this" changes

![Basic Bindings Asset](https://dev-to-uploads.s3.amazonaws.com/i/o0zwilq85weij70sj90z.gif)

Above is a basic demonstration of the `this` binding in action. At a high level, we can see that when `this` is returned within the arrow function, it is not pointing to the `level1obj` but rather to the global window context. On the other hand, the named function return `this` points to `level1obj`.

![Level 1 Basic This 001](https://dev-to-uploads.s3.amazonaws.com/i/a10dj8lfe086mcemk7n4.png)

We can see here that calling the named function and returning the `this` value results in `this` referring to our `level1obj` which allows us to do things like:

![Level 1 Basic This 002](https://dev-to-uploads.s3.amazonaws.com/i/zaj05ozy8wz51djzeyp7.png)

This allows us to access members of the `level1obj`.

![Level 1 Basic This 003](https://dev-to-uploads.s3.amazonaws.com/i/2s0ofwun50txgp1m2ejl.png)

On the other hand, when we access the arrowFunctions `this` that gets returned, we actually get the global `window` object. This is because the arrow function does not change the `this` context.

![Level 1 Basic This 004](https://dev-to-uploads.s3.amazonaws.com/i/on7mjwuepsugt6ars9hw.png)

Hence, accessing `testParam` with `this` will not work.

### When to use Named vs Arrow

Now that you know some basic on how the Arrow function changes `this`, here are some general guidelines for when to use Named functions vs Arrow functions.

### 1. Don't use arrow functions as members of an object

For reasons that we can see above. In the example given above, if for some reason within the function we have to access the members of the object (`level1obj` in the example), then we can't access them from within the function which will make things quite difficult.

### 2. Use arrow functions within callbacks

There is a deeper explanation for why this rule should be adhered to in the higher levels, but as a general guideline, arrow functions should be used in callbacks as you will be able to preserve your `this`.

### 3. Use arrow functions within dynamic contexts

By dynamic contexts, I mean anytime you are trying access or modify an object and its methods after the program runs. This usually appears when using events with some kind of event handler. When a callback function is passed to the event handler, the `this` reference points to the object that is listening for the event rather than the object that created the callback. Most times, it is advantageous to have the `this` reference point to the object that created it to modify its member variables or state. This is a common problem in React that arises when developers first learn about passing functions as props.

![Level 1 Dynamic Context](https://dev-to-uploads.s3.amazonaws.com/i/190ai2t1bn3pyjo4lpyr.gif)

Here we can see that when the Named Function is called within the class, the `this` context is not pointing to the class but rather the global window. 

On the other hand, the arrow function preserves the `this` context and can access the `Dynamic` classes's member variables within the callback function.

If you want to go more in-depth in the differences go to the next level!

---

<img style="margin-left: auto; margin-right: auto; display: block" src="https://dev-to-uploads.s3.amazonaws.com/i/oyx68dvyhjfm95ytskf8.png" alt="drawing" width="150"/>

## Level 2

Arrow functions have more differences than just the `this` context and for simplification, I spared the explanation on why the differences occur.

### Arguments Binding

Named functions have this feature called arguments binding. Utilizing the `new` keyword, you can create an instance of a function and store the arguments to a function within a variable.

![Arguments Binding Image](https://dev-to-uploads.s3.amazonaws.com/i/b6fwnxowwm4q1prp8nnp.png)

Here we can see that when utilizing a named function, we are able to bind the arguments by utilizing the `arguments` keyword within the function.

However, in the arrow function, it doesn't keep that reference to the `arguments` keyword.

### Constructable and Callable

Named functions are constructable and callable meaning that they are able to be called utilizing the `new` keyword, creating a new instance of the function, and are able to be called as regular functions.

Arrow functions, on the other hand, are only callable. This means that arrow functions cannot be called utilizing the `new` keyword.

![Constructable and Callable Image](https://dev-to-uploads.s3.amazonaws.com/i/ynfev91l2cp786zeoq42.png)

In the screenshot above, we can see that `new` could be used with named functions to create a new object. However, when utilized with the arrow function, the compiler gives an error: "TypeError: y is not a constructor".

### Generators

Named functions have access to a special keyword `yield`. This keyword along with a special syntax on the function declaration allows the function to become a `Generator function`. A generator function is one that can be exited and later re-entered where the information within the function context is saved even after exiting the function. If this sounds a bit confusing don't worry! What generator functions are, how they work, and use cases will be covered in another Gamify! series post.

While named functions have access to `yield`, arrow functions do not, meaning arrow functions cannot be generator functions.

![Generator Functions Gif](https://dev-to-uploads.s3.amazonaws.com/i/xlexngpcpze9dhlawlu4.gif)

Above we can see that when using the named function, we were able to create generator functions and utilize them with `yield`. However, when the same syntax was made the arrow function, the parser couldn't figure out what `yield` was.

### In-depth explanation of "this" context

In the previous level, we found several use cases of named and arrow functions based on how the `this` context changes. While I explained the "what" I haven't yet explained the "why".

When generalized, the rules of how the `this` context switches are fairly simple:

1. `new` keyword

The `new` keyword changes the context of the outermost `this` context for everything within that scope. This means that any functions defined within the object that gets created using `new` will have its `this` reference pointing to that new object. Let's see a very simple example of how this changes.

Normally in the global scope, `this` refers to either the window or undefined. If we were to create a new object with `new`, then if any of the functions within that new object reference `this`, they will point to the new object that was created.

![New Context Gif](https://dev-to-uploads.s3.amazonaws.com/i/5x2fnckve7k6glscfu25.gif)

Here we can see that we create a new `obj1` that logs its `this` reference and it points to itself. Within its member functions, it creates a new instance of `obj2` which logs it own `this` reference which points to its own member variables in both the named function and arrow function. 

The `new` keyword changes all of the `this` contexts of functions (both named and arrow) defined in its scope to point to instance of the newly instantiated object.

2. Callbacks

Callbacks makes things a bit messy. When encountering a  function declaration to find the `this` context, the outer scope needs to be identified. While the scope of normal variables are determined by the lexical scope, the `this` scope is determined by where it is called. Generally, the way callbacks work is that the compiler stores the context of where the callback function was passed as the callback's scope.

```javascript
let obj = {
    name: "test",
    cb() {
        return ("Hi", this.name)
    }
}

setTimeout(obj.cb, 1000)
```

In this example, this it will print out "Hi undefined". In this case, the callback "obj.cb" was defined in the global scope and as such the `this` reference will be lost and not set to `obj`.

Unlike named functions, arrow functions are treated as variables and thus are subject to the compiler's lexical scope. This means that within callbacks, there will be a difference in functionality with the `this` keyword.

![Callbacks Gif](https://dev-to-uploads.s3.amazonaws.com/i/oyle3qfvs9cvg50rxui2.gif)

We can see in the above example that when a named function is used within the callback, the `this` context becomes global as when setTimeout is invoked, where the callback gets defined and run is in the global context not in `obj`, hence the `this` context points to the window.

On the other hand, when an arrow function is used, since it is treated as a variable, it doesn't redefine the `this` context which is why it still points to `obj`.

3. Nested objects within classes

The simplest way to handle how named and arrow functions differ is to treat named functions as redefining `this` to the parent context of where it is defined and arrow functions as not redefining `this`.

![Nested Objs Gif](https://dev-to-uploads.s3.amazonaws.com/i/uqj6qu4pylposk030pw3.gif)

In this nested objects example, the named function `this` reference points to the innermost nested object while the arrow function `this` reference points to the outermost object. 

Thats all for this level, in the next one we will cover different instances and common patterns for fixing losing `this` context.

---

<img style="margin-left: auto; margin-right: auto; display: block" src="https://dev-to-uploads.s3.amazonaws.com/i/oyx68dvyhjfm95ytskf8.png" alt="drawing" width="150"/>

## Level 3

Here I wanted to cover several examples of using named vs arrow functions and explaining the results of each example.

1. Asynchronous Functions

![Asynchronous Functions Gif](https://dev-to-uploads.s3.amazonaws.com/i/0fflvpquo6csp8ribve1.gif)

With asynchronous functions, the binding of `this` follows the same rules as for regular functions and callbacks. In the example above, we can see that when using named functions for the callback to the Promise, we lose the context of `this` and it gets sent to the window. However, when we use arrow functions, we retain our context to the object. One aspect to note is that because our "arrowFunction" member variable is a named function, the `this` context within it points to the `obj`. If we had used an arrow function instead, it `this` would point to the window instead.

A takeaway we can note here is that, asynchronous functions don't change any differences between named and arrow functions, they both retain the same rules when used as regular functions and callbacks.

2. Classes

![Classes Gif](https://dev-to-uploads.s3.amazonaws.com/i/4ecn7c0c9fglk2745wc8.gif)

Within classes, the context of `this` changes due to the use of the `new` keyword. Because `new` is an identifier for detecting the start of a new context, both `namedFunction` and `arrowFunc` have their `this` context pointing to `class Testing`. 

Following the rule for callbacks mentioned previously, when we call `namedFunction` because of the use of named functions within the callbacks, the `this` context is lost within the Promise.

On the other hand, `arrowFunc` uses arrow functions in the callback handlers, so the `this` context is kept.
3. Object.create() and Prototypes

Prototypes are the method in which Javascript objects inherit base and additional features from one another. Using `Object.create()` syntax, you are able to create the equivalent of `classes` using prototypes in Javascript with Objects.create().

![Objects Prototypes Gif](https://dev-to-uploads.s3.amazonaws.com/i/bzyx0j6urpfrp6y91n4g.gif)

In the example above, using the prototype of the object `proto` I created a new object using `Object.create()`. Here it just creates a new object with the prototype that gets passed in meaning, `p` is a new object with the member variables and methods of `proto`.

In this scenario, `namedFunc` has a `this` reference to the member variables of `proto` but just returning `this` by itself shows an empty object. This is probably due to the fact that Javascript cannot determine whether `this` is referring to `proto` or the prototype for objects as Object.create() creates an object with the existing object as the prototype of the newly created object. 

When using `arrowFunc` there is no `new` keyword used here, even though we are creating a new object. This combined with the rules for arrow functions never change the `this` context, thus not changing it from pointing to the window.

### Patterns for fixing losing `this`

So how do we not lose `this` (nice pun)?

1. Using arrow functions

Arrow functions in Javascript are actually treated as variables that are bound to the lexical scope as opposed to functions (more on this in the next level). This is why arrow functions don't change the `this` context when created.

```javascript
const arrowFunc = () => {
    console.log(this)
}

function higherOrder(callback) {
    let obj = {
        name: "some new object"
    }
    
    obj.callback = callback

    obj.callback()
}

function namedFunction() {
    console.log(this)
}

higherOrder(namedFunction)
higherOrder(arrowFunc)
```

What do you think is going to be printed to the console in both cases?

Here `namedFunction` actually prints the `obj` that was defined within the `higherOrder` function while `arrowFunc` prints the global window. 

![Callback This Binding Gif](https://dev-to-uploads.s3.amazonaws.com/i/jqjxaxde7jt1wd8oyqp0.gif)

The reason this happens is because when `arrowFunc` was defined, it was treated as a **variable** meaning where `this` was referring to was already known as the lexer was able to scope the variable to the outermost scope.

However, with `namedFunction`, it is treated as a function and when it got passed into `higherOrder`, there was no way it could know what `this` was referring to until it was tied as a member function to `obj` within `higherOrder`

Because of this effect within callbacks, it is generally preferred to pass arrow functions within callbacks as the `this` context doesn't change as much and cause confusion.


2. Use `bind()`, `call()`, or `apply()`

When using `bind()` on a function, this returns a copy of the function with `this` pointing to the object passed into the bind function.

```javascript
let obj = {
  aProp: "this is a property",
  
  namedFunction() {
    console.log(this)
  }
  
}

let obj2 = {
  message: "When passed to bind, this object will be referenced by 'this'"
}

let funcBind = obj.namedFunction.bind(obj2)

obj.namedFunction() // returns obj

funcBind() // returns obj2
```

Here we can see that by using `bind()` we were able to bind the `this` reference to another object. When using `bind()` it expects a parameter that is an object to bind the `this` reference to and then returns a copy of the function with the `this` reference changed. Also, the original function is not changed as above, `obj.namedFunction()` still has its `this` pointing to itself.

A common pattern is for an object to pass itself in `bind()` so that its member function can be passed to another function as a callback, but still modify properties in the original object.

```javascript
class ChangeMe {
    constructor() {
        this.state = []
    }

    handleChange() {
        this.state = [1, 2, 3]
    }
}
```

Commonly used in React components, if `handleChange()` is passed as a prop to a child component without calling `bind()`, `this` will point towards the child component and will change the child state not the parent.

Using bind, however, we can fix this!

```javascript
class ChangeMe {
    constructor() {
        this.state = []

        this.bindHandleChange = this.handleChange.bind(this)
    }

    handleChange() {
        this.state = [1, 2, 3]
    }
}
```

There are two other functions: `apply()` and `call()` that have a similar functionality as `bind()` except, they call and run the function immediately.

```javascript
let obj = {
  aProp: "this is a property",
  
  namedFunction(param1, param2) {
    console.log(param1)
    console.log(param2)
    console.log(this)
  }
  
}

let obj2 = {
  message: "When passed bind, this object will be referenced by 'this'"
}

obj.namedFunction.apply(obj2, ["test", "test2"])
obj.namedFunction.call(obj2, "test", "test2")
```

Both apply and call takes the object to bind `this` to as the first parameter and run the function immediately. However, `apply()` takes an array of parameters, while `call()` takes parameters separated by commas.

`Bind()`, `call()`, and `apply()` all bind `this` to the object that gets passed in. In common cases, the class that owns that function usually binds its own `this` reference to the function in case that the function is used in a callback.

---

<img style="margin-left: auto; margin-right: auto; display: block" src="https://dev-to-uploads.s3.amazonaws.com/i/oyx68dvyhjfm95ytskf8.png" alt="drawing" width="150"/>

## Level 4

I know what some of you are thinking at this level, exactly why does Javascript treat named and arrow functions differently?
   
In this level lets take a look at the AST that gets generated from Javascript compilers, specifically **Node**.

```javascript
const { Parser } = require('acorn')

const namedAst = Parser.parse("function namedFunction() { return 1}")
console.log(namedAst)
const arrowAst = Parser.parse("const arrowFunction = () => {return 1}")
console.log(arrowAst)
```

I am just passing a very simple named function and arrow function in the form of a string to a package called **acorn** which is a package for a small Javascript parser that can generate the AST for a given Javascript program (for those that are not familiar, AST is [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree)).

![Named Function AST](https://dev-to-uploads.s3.amazonaws.com/i/c5zeezolmciblukqznrs.png)

Looking at the AST node output for a named function, we can see that it is of type **FunctionDeclaration**.

![Arrow Function AST](https://dev-to-uploads.s3.amazonaws.com/i/ib69rksjv190urtcxdjo.png)

On the other hand, an arrow function is treated as a node of type **VariableDeclaration**.

**FunctionDeclaration** and **VariableDeclaration** types are interesting, but we don't know what they are yet. After digging into the source code for the Node compiler, 
I was able to pin down some files where these types were referenced.

![Declare Function Source Code](https://dev-to-uploads.s3.amazonaws.com/i/45s6zhpwc6tax6rw7ybt.png)

From the Node compiler, this is the source code within **scopes.cc** to generatee the scope for default function variables.

Highlighted is a function within the same file that checks if the function is derived from an object and then assigns the `this` variable as a function local variable. 

In addition there is a function called `DeclareDynamicGlobal` that gets used within the declaration of the scope that references `this`, most likely to change it dynamically based on the current scope.

![Declare Scope Source Code](https://dev-to-uploads.s3.amazonaws.com/i/xvb5t4pwn943btcru5pz.png)

On the other hand for variable declarations, there is no changing of the `this` variable within its declaration.

![Declare Variable Source Code](https://dev-to-uploads.s3.amazonaws.com/i/3nlba2y8jrshdzzkh8wl.png)

There is more to this function, however, there was nothing reeferencing the two methods, `DeclareThis` and `DeclareDynamicGlobal` within this function for declaring the scope of variables.

While I am not too familiar with this source code as I haven't written or contributed to it, I think I was able to make a reasonable assumption as to why functions reassign `this` but variables do not.

## Conclusion

### If you made it this far congrats! :tada:

This was a part in the series of **Gamify!** where I try to write gamified tutorials that go in-depth (to the best of my ability) into a topic while also providing simplifications and steps towards learning more advanced knowledge within the topic. This time we covered Named vs Arrow functions, specifically, how they are the same, but also how they differ as well as providing solutions to common problems faced when handling those differences. Furthermore, we went in-depth into the AST of a Javascript  compiler to figure out why and how the compiler made those differences happen.