Functions and This

When I started writing JavaScript, I remember copy-pasting a lot of jQuery that made use of this, getting curious about what this actually meant, reading a little bit about it, and thinking "Yikes, I'll worry about that later." I also didn't really understand the difference between types of functions -- I mostly just thought arrow functions were cool and knew they did something weird with this.

Fast forward a few years, and having to explain this many times, it's not that scary! If you want to make use of classes in JavaScript, understand how React & Vue really work, or just become better at JavaScript in general, you need to get a grasp on this and how it works with different functions.

The different types of functions available to you in JavaScript are:

Named Functions

This is the classic way to declare a function. It fell out of favor for a while after arrow functions became the new hotness, but there's absolutely nothing wrong with declaring a function this way.

function someNamedFunction() {
	// Do stuff!
}

Anonymous Functions

Just like the named function above, but with no name and no reference. If you declare an anonymous function like this out in global scope without it being assigned to a variable, it will get garbage-collected:

function() {
	// Do stuff!
}

You would generally use an anonymous function as a callback, or assign it to a variable:

someOtherFunctionThatHasACallback(function() {
	// Do stuff!
});

// OR

const mySuperCoolFunction = function() {
	// Do stuff!
};

Arrow Functions

These are also anonymous, but are special in their own way, which I will describe after.

() => {
	// Do stuff!
}

The first two examples are very similar. One difference is that our named function can be called by name from anywhere that shares scope, but the anonymous function can only be called if it is assigned to a variable, or immediately invoked.

Arrow functions, however, stand out a bit. They are anonymous, so can only be called in the same ways as an anonymous function, but they can also perform an implicit return. This means that the function passes arguments into a one-line expression whose return is the return of the arrow function:

const add = (a, b) => a + b;
add(1, 2); // 3

This is most commonly used as shorthand in Array prototype methods:

const arr = [1, 2, 3];

arr.filter(num => num < 3); // [1, 2]

I hope that's a good jumping-off point for the next section. If you feel I missed anything, Tweet/DM me.

This

My favorite simple example to show how this works in relation to the different types of functions is this:

class SomeClass {
	constructor() {
		// Arrow function
		const arrow = (that) => {
			return that === this;
		};
		console.log(arrow(this));

		// Named function
		function someNamedFunction(that) {
			return that === this;
		}
		console.log(someNamedFunction(this));

		// Non-arrow anonymous
		const nonArrowAnonymous = function(that) {
			return that === this;
		}
		console.log(nonArrowAnonymous(this));
	}
}

new SomeClass();

This prints:

true
false
false

At a very high level, this is rebound to the scope of the non-arrow functions, and is not rebound to the scope of the arrow function.

This can be powerful to understand and will at the very least prevent you from running into many "gotchas" -- thanks for reading!