Search code examples
ecmascript-6traceur

Reference methods from another class in traceur


I'm testing classes in ES6 using traceur but it's not working as I expected.

I am trying to use a method as a reference in another class but when it's called I get the reference of the caller class when read the value of this.

Here is my code:

class A {
    constructor(anotherMethod){
        this.anotherMethod = anotherMethod;
        this.name = "A";
    }
    myMethod (){
        console.log(this.name);
        this.anotherMethod();
    }
}

class B {
    constructor(){
        this.a = new A(this.myMethod);
        this.name = "B";
    }
    myMethod(){
        console.log(this.name);
    }
}

var c = new B();
c.a.myMethod();

My expected log is:

A
B

But it is showing:

A
A

Solution

  • In class B, when the constructor function runs:

    this.a = new A(this.myMethod);
    

    You're actually setting the method myMethod of B to A. When A's constructor runs,

    this.myMethod, is set to A's anotherMethod. Now if you try printing this.a in your B's constructor you will get name : A. Which is actually referencing the class A.

    Now when you try executing the method, c.a.myMethod(), As A contains the reference to class A, it's invoking the myMethod of A. Inside this method, this will refer to the current execution context object which is A. That's the reason why you're seeing A in both the consoles.

    In short, You're only assigning the function to A and not setting the context.

    You can force fat arrow using below:

    class B {
        constructor(){
            this.a = new A(this.myMethod);
            this.name = "B";
        }
    
         myMethod = () => {
                console.log(this);
         }
    }
    

    Now you will get the desired output. But unfortunately traceur doesn't support it. Only babel supports fat arrow inside functions which is part of ES7 stage 0 Class Properties.

    As suggested by Felix King: Binding the context using bind is more than enough currently

    class B {
        constructor(){
            this.a = new A(this.myMethod.bind(this));
            this.name = "B";
        }
    
         myMethod() {
                console.log(this);
         }
    }