problem understanding "this" in a classic and arrow function called as callback

Viewed 35

I recently face a problem that I can understand yet. Is about the this keyword difference in a classical function vs. arrow function but when it is called as callback. Let me example that:

Ex. 1

class ProductController {
    static property = "hello world"
    
    static findAll() {
        console.log(this.property)
    }
}


// Function that calls findAll
const router = function( callback ) {
    callback()
}

Ex. 1, call 1: If I call this function normally as ProductController.findAll() output will be: hello world. All okay.

Ex. 1, call 2: If I call this function as callback like router(ProductController.findAll) output will be: Cannot read property 'property' of undefined

In this call 2, this is undefined because the findAll function is passed as value to the router (I guess) where the this reference is loosed, right? All good here.


Now let's took a variant of this code using arrow functions, as follows:

Ex. 2

class ProductController {
    static property = "hello world"
    
    static findAll = () => {
        console.log(this.property)
    }
}


// Function that calls findAll
const router = function( callback ) {
    callback()
}

Ex. 2, call 1: If I call this function normally as ProductController.findAll()output will be: hello world. It's fine.

Ex. 2, call 2: If I call this function as callback like: router( ProductController.findAll ) output will be: hello world. WTF, I can't understand this behavior!

In call 2, I guess the function is passed as value and not by reference so I can't understand why this still references to the class...


Help understanding that please

1 Answers

If I call this function as callback like: router( ProductController.findAll ) output will be: hello world. WTF, I can't understand this behavior!

Arrow functions generally inherit their this from the outer scope. For static members which are arrow functions (which is very new syntax!), the this is the class itself. You can think of the second example code like this:

class ProductController {
    static property = "hello world"
    
    static findAll = () => {
        console.log(that.property)
    }
}
const that = ProductController;

Or like this psuedocode:

class ProductController {
    using (this as ProductController) {
        this.property = "hello world"
        this.findAll = () => {
            console.log(this.property);
        }
    }
}

Since it's defined with an arrow function, it doesn't matter how callback() happens to be called - the this is determined solely from where the function is declared, and not from how it may be passed around as a callback.

Related