0

Very weird behaviour. Why does the following log "A.fn" only, the next line "B.fn" doesn't even run? What exactly is happening in this following code?

I'm using Babel stage-2, which is used in most React projects.

class A {
    fn = () => {
        console.log("A.fn");
    }
}

class B extends A {
    fn() {
        super.fn();
        console.log('B.fn')
    }
}

new B().fn(); // why this logs "A.fn" only, while "B.fn" isn't logged?
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Maria
  • 3,455
  • 7
  • 34
  • 47

1 Answers1

2

Can I know exactly what's happening in this following code?

Public class fields is equivalent to doing:

class A {
  constructor() {
    this.fn = () =>  console.log("A.fn");
  }
}

I.e. fn is defined on the instance itself whereas when using the method syntax, the method is defined on the prototype (B.prototype.fn). Lets log an instance of B:

enter image description here

The first fn is the one created in the constructor, the second one is the defined as B's class methods. Because fn is defined on the instance, i.e. is "higher" in the prototype chain, it shadows B.prototype.fn, meaning that B.prototype.fn is never called.

That's just how the prototype chain works!

Here is a simpler example with the same problem:

const proto = {fn() { console.log('proto'); }};
const obj = Object.create(proto);
obj.fn = () => console.log('instance');
obj.fn();
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    …and what is even worse about class fields: Using `fn = () => {` in the `class B` doesn't fix this. – Bergi Jun 11 '18 at 20:05
  • `{fn() { console.log('proto'); }};` is not correct syntax..? – Maria Jun 11 '18 at 21:05
  • @JohnLee: Yes it is. Try to run the code snippet. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions – Felix Kling Jun 12 '18 at 00:21