Skip to main content
โšก Calmops

The 'this' Keyword and Context Binding

The ’this’ Keyword and Context Binding

The this keyword refers to the object that a function belongs to. Understanding this is crucial for object-oriented JavaScript.

What is ’this'?

this refers to the context in which a function is executed:

const person = {
    name: "Alice",
    greet: function() {
        console.log(this.name);
    }
};

person.greet(); // "Alice" - this refers to person

Global Context

In global scope, this refers to the global object:

// In browser
console.log(this); // window object

// In Node.js
console.log(this); // global object (or module.exports)

Function Context

When a function is called without an object, this is the global object (or undefined in strict mode):

function test() {
    console.log(this);
}

test(); // window (browser) or global (Node.js)

Strict Mode

In strict mode, this is undefined:

"use strict";

function test() {
    console.log(this); // undefined
}

test();

Method Context

When a function is called as a method, this refers to the object:

const calculator = {
    value: 0,
    add: function(n) {
        this.value += n;
        return this;
    },
    subtract: function(n) {
        this.value -= n;
        return this;
    },
    getValue: function() {
        return this.value;
    }
};

calculator.add(5).subtract(2);
console.log(calculator.getValue()); // 3

Method Extraction Problem

const person = {
    name: "Alice",
    greet: function() {
        console.log(this.name);
    }
};

const greet = person.greet;
greet(); // undefined - this is now global

call() Method

Call a function with a specific this context:

function greet(greeting) {
    return `${greeting}, ${this.name}!`;
}

const person = { name: "Alice" };

console.log(greet.call(person, "Hello")); // "Hello, Alice!"

Multiple Arguments

function introduce(greeting, punctuation) {
    return `${greeting}, I'm ${this.name}${punctuation}`;
}

const person = { name: "Bob" };

console.log(introduce.call(person, "Hi", "!")); // "Hi, I'm Bob!"

apply() Method

Similar to call(), but arguments are passed as an array:

function greet(greeting, punctuation) {
    return `${greeting}, ${this.name}${punctuation}`;
}

const person = { name: "Charlie" };

console.log(greet.apply(person, ["Hello", "!"])); // "Hello, Charlie!"

Practical Use: Math Functions

const numbers = [5, 6, 2, 3, 7];

const max = Math.max.apply(null, numbers);
console.log(max); // 7

// Or with spread operator
const max2 = Math.max(...numbers);
console.log(max2); // 7

bind() Method

Create a new function with a fixed this context:

function greet(greeting) {
    return `${greeting}, ${this.name}!`;
}

const person = { name: "Diana" };

const greetPerson = greet.bind(person);
console.log(greetPerson("Hello")); // "Hello, Diana!"

Partial Application

function multiply(a, b) {
    return a * b;
}

const double = multiply.bind(null, 2);
console.log(double(5)); // 10
console.log(double(10)); // 20

Event Handlers

const button = {
    label: "Click me",
    handleClick: function() {
        console.log(this.label);
    }
};

// Without bind - this is the button element
// element.addEventListener("click", button.handleClick);

// With bind - this is the button object
// element.addEventListener("click", button.handleClick.bind(button));

Arrow Functions and this

Arrow functions don’t have their own this - they inherit from parent scope:

const person = {
    name: "Eve",
    greet: function() {
        console.log(this.name); // "Eve"
    },
    greetArrow: () => {
        console.log(this.name); // undefined (this is global)
    }
};

person.greet(); // "Eve"
person.greetArrow(); // undefined

Arrow Functions in Methods

const person = {
    name: "Frank",
    hobbies: ["reading", "gaming"],
    listHobbies: function() {
        this.hobbies.forEach(hobby => {
            console.log(`${this.name} likes ${hobby}`);
        });
    }
};

person.listHobbies();
// Frank likes reading
// Frank likes gaming

Practical Examples

Class Methods

class Counter {
    constructor(initial = 0) {
        this.count = initial;
    }
    
    increment() {
        this.count++;
        return this.count;
    }
    
    decrement() {
        this.count--;
        return this.count;
    }
    
    getCount() {
        return this.count;
    }
}

const counter = new Counter(10);
console.log(counter.increment()); // 11
console.log(counter.decrement()); // 10

Event Handler with Context

class Button {
    constructor(element) {
        this.element = element;
        this.clickCount = 0;
        
        // Bind the handler to maintain this context
        this.element.addEventListener("click", this.handleClick.bind(this));
    }
    
    handleClick() {
        this.clickCount++;
        console.log(`Clicked ${this.clickCount} times`);
    }
}

// Usage
// const btn = new Button(document.getElementById("myButton"));

Callback with Context

const user = {
    name: "Grace",
    friends: ["Henry", "Iris", "Jack"],
    listFriends: function() {
        this.friends.forEach(function(friend) {
            console.log(`${this.name} is friends with ${friend}`);
        }.bind(this)); // Bind this to user object
    }
};

user.listFriends();
// Grace is friends with Henry
// Grace is friends with Iris
// Grace is friends with Jack

Method Chaining

const calculator = {
    value: 0,
    add(n) {
        this.value += n;
        return this; // Return this for chaining
    },
    multiply(n) {
        this.value *= n;
        return this;
    },
    subtract(n) {
        this.value -= n;
        return this;
    },
    result() {
        return this.value;
    }
};

const result = calculator
    .add(5)
    .multiply(2)
    .subtract(3)
    .result();

console.log(result); // 7 (5 + 5 = 10, 10 * 2 = 20, 20 - 3 = 17... wait, let me recalculate)
// Actually: (0 + 5) * 2 - 3 = 10 - 3 = 7

call vs apply vs bind

Method Syntax Invokes Use Case
call() fn.call(obj, arg1, arg2) Immediately Direct invocation
apply() fn.apply(obj, [arg1, arg2]) Immediately Array of arguments
bind() fn.bind(obj, arg1, arg2) Returns function Event handlers, callbacks

Common Mistakes

Losing Context

// Problem
const person = {
    name: "Henry",
    greet: function() {
        console.log(this.name);
    }
};

const greet = person.greet;
greet(); // undefined - lost context

// Solution
const greet2 = person.greet.bind(person);
greet2(); // "Henry"

Arrow Functions in Objects

// Problem - arrow function loses this
const obj = {
    name: "Iris",
    greet: () => {
        console.log(this.name); // undefined
    }
};

// Solution - use regular function
const obj2 = {
    name: "Jack",
    greet: function() {
        console.log(this.name); // "Jack"
    }
};

Summary

  • this: refers to the object context
  • Global: this is global object (or undefined in strict mode)
  • Method: this refers to the object
  • call(): invoke with specific this
  • apply(): invoke with this and array of arguments
  • bind(): create new function with fixed this
  • Arrow functions: inherit this from parent scope
  • Best practice: be explicit about context

Official Documentation

Next Steps

  1. ES6 Classes: Syntax and Features
  2. Closures: Understanding Function Scope
  3. Callbacks and Asynchronous JavaScript

Comments