1

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
Igor
  • 655
  • 7
  • 10
  • possible duplicate of [How to access the correct \`this\` / context inside a callback?](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) – Felix Kling Apr 03 '15 at 07:23
  • *"but when it's called I get the reference of the caller class when read the value of `this`"* That's simply how `this` works in JavaScript. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this – Felix Kling Apr 03 '15 at 07:24
  • @FelixKling I understand that. But it is confusing because you don't have an universal variable to access the current class instance. You can't rely on 'this' variable if you are not sure on how your methods will be used by others. – Igor Jun 01 '15 at 05:26
  • That's true. However, if the methods are not called as intended, then they probably won't work, in which case someone will likely change the code to make it work (and call them as intended). You shouldn't have to consider the mistakes others might make. What you should do is provide a clear API and documentation. If someone doesn't use library correctly, it's their problem. – Felix Kling Jun 01 '15 at 05:28

1 Answers1

2

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);
     }
}
mohamedrias
  • 18,326
  • 2
  • 38
  • 47
  • Ok, but it's not the expected behavior of classes, right? If you write similar code in another languages it will work. In coffeescript it work if you use the fat arrow, but traceur do not support fat arrow in methods, or does it? – Igor Apr 03 '15 at 05:13
  • It raises "Unexpected token". – Igor Apr 03 '15 at 06:56
  • Yes traceur doesn't support fat arrow inside methods – mohamedrias Apr 03 '15 at 07:13
  • The explanation is correct, but arrow functions don't solve that problem. Arrow functions resolve `this` in the *lexical* scope. So in this example `this` resolves to the global object or the module's `this` (which is `undefined`). – Felix Kling Apr 03 '15 at 07:22
  • 2
    Ah I see now. The actual feature you are using is **class properties** (`class A { foo = bar }`). This is an ES7 stage 0 proposal: http://babeljs.io/docs/usage/experimental/, https://gist.github.com/jeffmo/054df782c05639da2adb . I wouldn't really recommend using it at this point. Simply calling `new A(this.myMethod.bind(this));` would work just as well. – Felix Kling Apr 03 '15 at 07:30