Skip to content

Instantly share code, notes, and snippets.

@nax3t
Created December 1, 2024 11:05
Show Gist options
  • Save nax3t/cfe2defbb6a3db7f6677f14149abb243 to your computer and use it in GitHub Desktop.
Save nax3t/cfe2defbb6a3db7f6677f14149abb243 to your computer and use it in GitHub Desktop.
Learn about `this` in Javascript in the context of Call, Apply, Bind, and Arrow Functions

Understanding 'this' and Function Binding in JavaScript

A Beginner's Guide

1. What is 'this'?

Let's start with the most important (and confusing) concept: the this keyword. In JavaScript, this refers to the current execution context - basically, who's running the code right now.

// Example 1: 'this' in a regular object
const person = {
    name: "Alice",
    sayHi: function() {
        console.log("Hi! My name is " + this.name);
    }
};

person.sayHi();  // Output: "Hi! My name is Alice"

Here, when sayHi runs, this refers to the person object because that's who called the function.

2. The Problem with 'this'

But 'this' can be tricky! Watch what happens when we use the same function in a different context:

const person = {
    name: "Alice",
    sayHi: function() {
        console.log("Hi! My name is " + this.name);
    }
};

const justTheFunction = person.sayHi;
justTheFunction();  // Output: "Hi! My name is undefined"

What happened? When we called the function directly, this was no longer bound to our person object. This is where call, apply, and bind come to help!

3. Call

call lets us explicitly set what this should be when calling a function:

const person1 = { name: "Alice" };
const person2 = { name: "Bob" };

function greet() {
    console.log("Hello! I'm " + this.name);
}

greet.call(person1);  // Output: "Hello! I'm Alice"
greet.call(person2);  // Output: "Hello! I'm Bob"

You can also pass arguments after the this value:

function greetWithMessage(message) {
    console.log(message + ", I'm " + this.name);
}

greetWithMessage.call(person1, "Good morning");  // Output: "Good morning, I'm Alice"

4. Apply

apply is almost identical to call, but it takes arguments as an array:

function introduce(greeting, hobby) {
    console.log(greeting + ", I'm " + this.name + " and I like " + hobby);
}

// With call:
introduce.call(person1, "Hi", "coding");

// With apply:
introduce.apply(person1, ["Hi", "coding"]);

// Both output: "Hi, I'm Alice and I like coding"

Think of it this way: A for Array = Apply takes an array of arguments

5. Bind

While call and apply immediately call the function, bind creates a new function with this permanently set:

const person = {
    name: "Alice",
    sayHi: function() {
        console.log("Hi! My name is " + this.name);
    }
};

const functionForAlice = person.sayHi.bind(person);

// Now this will work correctly:
functionForAlice();  // Output: "Hi! My name is Alice"

// bind is permanent - this won't change the binding:
const otherPerson = { name: "Bob" };
functionForAlice.call(otherPerson);  // Still outputs: "Hi! My name is Alice"

6. Arrow Functions: The Modern Solution

Arrow functions handle this differently - they inherit this from their surrounding code:

const person = {
    name: "Alice",
    // Traditional function with setTimeout
    sayHiLater: function() {
        setTimeout(function() {
            console.log("Hi! My name is " + this.name);  // this.name will be undefined!
        }, 1000);
    },
    // Arrow function with setTimeout
    sayHiLaterArrow: function() {
        setTimeout(() => {
            console.log("Hi! My name is " + this.name);  // Works correctly!
        }, 1000);
    }
};

person.sayHiLater();      // Output after 1s: "Hi! My name is undefined"
person.sayHiLaterArrow(); // Output after 1s: "Hi! My name is Alice"

Quick Reference:

  1. call(thisArg, arg1, arg2, ...) - Call function with specific this and arguments listed out
  2. apply(thisArg, [arg1, arg2, ...]) - Call function with specific this and arguments as array
  3. bind(thisArg) - Create new function with this permanently set
  4. Arrow functions () => - Inherit this from surrounding code

Practice Exercise:

Try this code and predict the output:

const calculator = {
    value: 0,
    add: function(a, b) {
        return this.value + a + b;
    }
};

const calculator2 = {
    value: 100
};

console.log(calculator.add(5, 3));                    // What's this?
console.log(calculator.add.call(calculator2, 5, 3));  // What's this?
console.log(calculator.add.apply(calculator2, [5, 3])); // What's this?

const boundAdd = calculator.add.bind(calculator2);
console.log(boundAdd(5, 3));                         // What's this?

Solutions:

  1. First log: 8 (0 + 5 + 3)
  2. Second log: 108 (100 + 5 + 3)
  3. Third log: 108 (100 + 5 + 3)
  4. Fourth log: 108 (100 + 5 + 3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment