Search code examples
javascriptes6-classfunction-expressionclass-fields

JS Class: Difference between ES6 myFunc(){..} and ES5 myFunc = function() {...} in a class declaration


In the following code,

class PersonClass {
  constructor(fname) {
    this.fname = fname;
  }
  read = function() { console.log('I am reading') }
  speak () { console.log('I am speaking'); }
}

//Instantiate 
let p1 = new PersonClass('Raj')

read = function() { console.log('I am reading') } becomes a property of newly created instance i.e.

p1.hasOwnProperty('read') is true

as opposed to speak() { console.log('I am speaking'); } gets assigned to PersonClass.prototype. i.e.

p1.hasOwnProperty('speak') is False

p1.__proto__.hasOwnProperty('speak') is true

Can somebody pls explain why this happens.

Essentially what's the diff between two way of method declarations inside class.

I thought speak() {...} was just shorter syntax for speak = function() {...} (in ES6)

Thanks


Solution

  • The

    read = function() { console.log('I am reading') }
    

    is new class field syntax. It's effectively the same as assigning to the read property of the instance inside the constructor:

    class PersonClass {
      constructor(fname) {
        this.read = function() {
          console.log('I am reading')
        }
        this.fname = fname;
      }
      speak() {
        console.log('I am speaking');
      }
    }
    

    speak, on the other hand, is an ordinary class method, which means it's on the prototype, PersonClass.prototype, which is the same thing as Object.getPrototypeOf(p1), which is the same thing as p1.__proto__ (deprecated syntax).

    class PersonClass {
      constructor(fname) {
        this.read = function() {
          console.log('I am reading')
        }
        this.fname = fname;
      }
      speak() {
        console.log('I am speaking');
      }
    }
    let p1 = new PersonClass('Raj')
    console.log(
      PersonClass.prototype.hasOwnProperty('speak'),
      Object.getPrototypeOf(p1) === PersonClass.prototype,
      p1.__proto__ === PersonClass.prototype
    );

    So, the speak property is on the internal prototype of the instance, not on the instance itself. The read property is a direct property of the instance, just like the fname property.

    Keep in mind that class field syntax is still an experimental proposal (stage 3). It's implemented in Chrome, at least, but it's not completely official yet.