Search code examples
javascriptthisbind

Why is JavaScript's bind() not working here as I expect it?


class Test {
    DISPATCH_TABLE = {
        "Outer Method": this.outerMethod
    }
    innerMethod() {
        console.log("success");
    }
    outerMethod() {
        console.log(this);
        this.innerMethod();
    }
    dispatch(method_name) {
        this.DISPATCH_TABLE[method_name]()
    }
    constructor() {
        this.outerMethod = this.outerMethod.bind(this)
    }
}
t = new Test()
t.dispatch("Outer Method")

This logs the dispatch table itself and then prints the error, "this.innerMethod is not a function". I understand why this would be bound to the dispatch table without the bind() call in the constructor, but I thought that including that call was supposed to force this to refer to the class in any calls to the bound method.

I'm not blaming JavaScript or bind() for my expectation. I just don't know why my expectation is wrong.

I could just use a switch statement instead of a dispatch table, but I'd prefer to use a dispatch table if I can.


Solution

  • You'll probably have a better time using arrow functions, which are always correctly this-bound.

    I took the liberty of changing your dispatch table to map "verbose names" of function to internal method names, too.

    class Test {
      DISPATCH_TABLE = {
        "Outer Method": "outerMethod",
      };
      innerMethod = () => {
        console.log("success");
      };
      outerMethod = () => {
        console.log(this);
        this.innerMethod();
      };
      dispatch(method_name) {
        const meth = this[this.DISPATCH_TABLE[method_name]];
        if (!meth) throw new Error(`no such method ${meth}`);
        return meth();
      }
    }
    t = new Test();
    t.dispatch("Outer Method");