Arrow Functions & this - The Simple Rules

Golden Rule: Arrow functions are this-blind. They steal this from their parent scope (where they’re written, not called).

Rule 1: Arrow Functions Don’t Have Their Own this

javascript

function normalFunc() {
    console.log(this); // Has its own 'this'
}
 
const arrowFunc = () => {
    console.log(this); // Borrows 'this' from outside
};

Rule 2: They Look UP the Scope Chain for this

Step-by-step process:

  1. Arrow function needs this
  2. “I don’t have this, let me check my parent”
  3. Goes up one level in scope
  4. If parent has this, use that
  5. If parent is also arrow function, keep going up
  6. Eventually finds a regular function or global scope

Common Scenarios:

Scenario 1: Arrow in Object (DOESN’T WORK)

javascript

const obj = {
    name: "John",
    greet: () => {
        console.log(this.name); // undefined
    }
};
 
obj.greet(); // undefined

Why: Arrow function looks for parent scope → finds global scope → this = undefined

Scenario 2: Arrow Inside Method (WORKS)

javascript

const obj = {
    name: "John",
    greet() { // Regular method - has 'this = obj'
        const arrow = () => {
            console.log(this.name); // "John"
        };
        arrow();
    }
};
 
obj.greet(); // "John"

Why: Arrow function looks up → finds greet() method → steals its this = obj

Scenario 3: Nested Arrows

javascript

const obj = {
    name: "John",
    greet() { // this = obj
        const arrow1 = () => { // steals from greet: this = obj
            const arrow2 = () => { // steals from arrow1: this = obj
                console.log(this.name); // "John"
            };
            arrow2();
        };
        arrow1();
    }
};

Step-by-Step Decision Tree:

When you see an arrow function using this:

  1. Is it directly in an object?this = undefined/window

    javascript

    const obj = { arrow: () => this }; // Global 'this'
  2. Is it inside a regular method?this = object

    javascript

    const obj = {
        method() { // this = obj
            const arrow = () => this; // steals obj
        }
    };
  3. Is it inside another arrow? → Keep going up until you find regular function

    javascript

    const obj = {
        method() { // this = obj
            const arrow1 = () => { // this = obj
                const arrow2 = () => this; // this = obj
            };
        }
    };
  4. Is it in global scope?this = undefined (strict) or window

    javascript

    const arrow = () => this; // Global scope

Common Interview Traps:

Trap 1: Looks like it should work

javascript

const user = {
    name: "John",
    greet: () => console.log(`Hi ${this.name}`) // undefined!
};

Trap 2: setTimeout with arrow vs regular

javascript

const obj = {
    name: "John",
    test() {
        // Arrow - inherits 'this' from test()
        setTimeout(() => console.log(this.name), 100); // "John"
        
        // Regular - loses 'this' in setTimeout
        setTimeout(function() { console.log(this.name); }, 100); // undefined
    }
};

Trap 3: Event handlers

javascript

const obj = {
    name: "John",
    setupHandler() {
        // Arrow - keeps 'this = obj'
        button.onclick = () => console.log(this.name); // "John"
        
        // Regular - 'this' becomes button element
        button.onclick = function() { console.log(this.name); }; // undefined
    }
};

Visual Scope Chain:

javascript

// Global scope (this = undefined/window)
const obj = {
    name: "John",
    
    // Object literal (no function scope, still global)
    badArrow: () => this, // Global 'this'
    
    // Method scope (this = obj)
    goodMethod() {
        // Arrow inherits from method
        const arrow = () => this; // obj's 'this'
        
        function inner() {
            // Regular function (this = undefined)
            const arrow2 = () => this; // undefined
        }
    }
};

The Mental Model:

Think of arrows as “transparent to this”:

  • They’re like windows - you see through them to find the real this
  • Keep looking up scopes until you find a regular function or global scope
  • Whatever this that scope has, the arrow uses

Quick Check:

  1. Find the arrow function
  2. Go up one scope level
  3. Is it a regular function? Use its this
  4. Is it another arrow? Keep going up
  5. Hit global scope? Use global this

Bottom line: Arrows inherit this from their writing location, not calling location. They look up the scope chain until they find a regular function with this.