2

I am passing a class method as a parameter to a new class instantiation like this:

class Abc {
    constructor() {
        this.a = () => { };
    }
    b = new Def(this.a);
}

I get 'cannot read property a of undefined' in browser console. Why is a undefined inside b = new Def(this.a)? On debugging, I found that browser throws the error and the constructor code is never reached. Why is this happening?

Note: I am using babel, so I can use class fields and hence b = new Def() is a valid syntax here.

darKnight
  • 5,651
  • 13
  • 47
  • 87
  • Works for me https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=AQ4YwGwQwZx4CCAjMwDeAoU3hQBQCU6wAvgNxY4hLAC8wAdgKYDuwAIkwGZ4AuAFgEsYAOigEK2EhkohIseJy7pZoMAHsGMXgCcArmF7qdecSqrhNMdRCYiI6gOamCqkCRCrpqjVpt2HZwByAGsQoIAaRlZEFAIgA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=false&presets=es2015%2Cstage-2&prettier=true&targets=&version=6.26.0&envVersion=1.6.2 – Yury Tarabanko Apr 01 '18 at 15:29
  • Could you recreate a working example demonstrating the issue? – Yury Tarabanko Apr 01 '18 at 15:31
  • I can't post the exact code as I am working on a remote machine that blocks posting to stackoverflow. However, I realised that the problem is with initializing the concerned variable. From the question's context, I am initializing `a` inside `constructor` of `Abc`, like `this.a = () => {}`. I found on debugging that the program is not oddly not going inside the `constructor`, so `this.a=...` never gets executed, and hence `this.a` is undefined. But I can't understand why the constructor code is not getting executed? Have modified code in question to reflect this. – darKnight Apr 01 '18 at 16:42

1 Answers1

3

That's how class fields work, they are evaluated before constructor body (but after super()). Line 1 is evaluated before line 2, and the order in which constructor and b field are ordered doesn't matter:

constructor() {
    this.a = () => { }; // 2
}
b = new Def(this.a); // 1

Since class fields are already in use, in order to maintain proper execution order it should be:

a = () => { }; // 1
b = new Def(this.a); // 2

constructor() {}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thanks for the clarification. However, in my code, the function `a` uses some value passed while creating new instance of `Abc`, and hence I can only capture that in the constructor, so the code `this.a = () => { };` must be in the constructor only. – darKnight Apr 01 '18 at 17:15
  • Or is there any way around this? – darKnight Apr 01 '18 at 17:34
  • 2
    Then move `b = new Def(this.a)` to constructor body. Class fields are just syntactic sugar for constructor code. – Estus Flask Apr 01 '18 at 17:52
  • I just tried this out, and I see that the constructor code is running before class fields are parsed. Check this out: https://jsfiddle.net/dk49/qr2a6945/4/ – darKnight Apr 01 '18 at 18:23
  • No, it isn't. `this.x` is used after construction(`y.a()` call), so the order in which x and a are defined doesn't matter. It's always helpful to check transpiler output in case when you're unsure what's going on, https://babeljs.io/repl/#?code_lz=AQ4YwGwQwZx4CCAjMwDeAoU3wHsB2MALgE4CuYRuJAFAB4CU6WOIAJgKZJkDmPHJANwtWASCIALAJYwAdHWABeYHWGtWYAjFwQOsiLh40A5AElCUzsADCW0hSokAXMGMAaYJJnyGa9QF8RHCglYBoGRQA-NE1CHT0DI2MAeTIiGEsOGztySmoXd09pOUZ_QWAgwKDY4mAAT1D8DgB3RBQTAClcCXxjXwxRUTrZKHDBIA&presets=es2015%2Cstage-0 – Estus Flask Apr 01 '18 at 18:34
  • Hmm..but how is `console.log('Inside Constructor: ', this.x);` printing the right value of `x` when `this.x = x` is executing after it? – darKnight Apr 01 '18 at 18:40
  • Same way as `function bar() { console.log(foo) }; var foo = 1; bar()` would work. No, it's not executed after it. `this.x = ...` is executed after `this.a = () =>/* doesn't matter what's here*/`. When you define a function, it's not executed automatically. Remove `y.a()`, and you'll see that console.log is never executed. – Estus Flask Apr 01 '18 at 18:49