same method or variable name in a javascript class behaves differently

147 Views Asked by At
class Parent{
    method(){
        console.log("Parent");
    }
}
class Child extends Parent{
    method(){
        console.log("Parent");
    }
}
var child = new Child();
console.log(child.method);

console return method in child class which is a expected behaviour.

class Parent{
    method = "sss"
}
class Child extends Parent{
    method(){
        console.log("Child")
    }
}
var child = new Child();
console.log(child.method)

why does the console return method variable - "sss" in Parent class ?

2

There are 2 best solutions below

5
Quentin On

From MDN

Public instance fields are added to the instance either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass.

i.e. it masks the method because it is assigned around the time the constructor runs.

child.method is a property (with a value that is a string) on the object itself. This masks the method on the prototype which is a function.


The code below demonstrates.

You can see that in example a (your code) the string value for method is a property of child itself, but you can dig through the prototype chain to get the function value from the class.

In example b (with the public instance field removed), the method exists and can be called, but isn't on the child itself (because its an instance of the class so it can search the prototype chain automatically because it isn't masked).

const a = () => {
  class Parent {
    method = "sss"
  }
  class Child extends Parent {
    method() {
      console.log("Child")
    }
  }
  var child = new Child();
  console.log("a: " + child.hasOwnProperty('method'));
  Object.getPrototypeOf(child).method();
};

a();

const b = () => {
  class Parent {}
  class Child extends Parent {
    method() {
      console.log("Child")
    }
  }
  var child = new Child();
  console.log("b: " + child.hasOwnProperty('method'));
  child.method();
};

b();

0
3limin4t0r On
class Parent {
    method = "sss";
}

Is essentially a shortcut for:

class Parent {
    constructor() {
        this.method = "sss";
    }
}

Meaning that there are some important differences with:

class Parent {
    method() {
        console.log("Parent");
    }
}
  1. In the method = "sss" variant, method will be set as an own property of the created instance (new Child()).

    child.hasOwnProperty("method") //=> true
    

    Whereas defining a normal method method() { console.log("Parent") } will not be set as an own property of the instance. Instead it is set on the prototype chain.

    Parent.prototype.hasOwnProperty("method") //=> true
    
  2. The constructor code only runs whenever you initialize an instance. Meaning that this.method = "sss" will always run after you've defined the Parent and Child classes (whenever you create the instance with new).

class Parent {
    prop = "parent value";
    // aka
    // constructor() {
    //   this.prop = "parent value";
    // }
    method() {
        console.log("Parent");
    }
}

class Child extends Parent {
    prop() {
      return "child Value";
    }
    method() {
        console.log("Child");
    }
}

const child = new Child();

const log = (jsString) => console.log(jsString, '//=>', eval(jsString));
log(`child.hasOwnProperty("prop")`);
log(`child.hasOwnProperty("method")`);
log(`Parent.prototype.hasOwnProperty("prop")`);
log(`Parent.prototype.hasOwnProperty("method")`);

The final Child instance structure looks like this:

new Child()
// returns
Child{ // Child instance depicted using object notation
  // own properties
  prop: "parent value", // set by the Parent constructor

  // prototype chain depicted using the __proto__ (deprecated) property
  __proto__: {
    // Child.prototype
    prop() { return "child Value" },
    method() { console.log("Child") },

    __proto__: {
      // Parent.prototype
      method() { console.log("Parent") },
    }
  }
}

For more detailed info I suggest reading through the MDN Public class fields page.