0

I'm currently learning Javascript class. and I've got a question about class method override.

subclass method without using function keyword

class Class {
    
    m = function() {
        console.log('super')
    }
}

class Subclass extends Class{
  
    m() {
        console.log('sub')
    }
}

const si = new Subclass()

si.m() // super

I think it should print out 'sub' because Subclass has method m, which I think would override method m in its super class Class.

If I change subclass method using function keyword, then I get what I expected.

...

class Subclass extends Class{
    m = function() {
        console.log('sub')
    }
}

...

si.m() // sub

Why it is working like these? What's the difference between methods w and w/o function keyword?

hoo
  • 67
  • 4
  • [Duplicate](//google.com/search?q=site%3Astackoverflow.com+js+class+method+vs+class+field+function) of [What is the difference between class method vs property function vs property arrow function in typescript?](/q/56055658/4642212). – Sebastian Simon Jul 29 '21 at 03:53

1 Answers1

3

The = uses class field syntax, which is syntax sugar for assigning the property to the instance in the constructor, right after any super calls. This

class Class {
    
    m = function() {
        console.log('super')
    }
}

is the same as

class Class {
    constructor() { 
        this.m = function() {
            console.log('super')
        }
    }
}

Using m() syntax puts the function not on the instance, but on the prototype. That is

si.hasOwnProperty('m')

would return true when using class fields, and false when using m() (method syntax). And

si.prototype.hasOwnProperty('m')

would return false when using class fields, and true when using method syntax.

Another small difference is that when using method syntax, the function can't be used as a constructor with new.

With your code, the superclass puts m directly on the instance. When using method syntax in the subclass, the subclass's m is not seen when referencing the instance because the m property exists earlier in the prototype chain - on the instance, not on the subclass prototype. When you change the subclass to declare m as a class field, you're putting it directly on the instance, overwriting the superclass's assignment to the instance.

I'd usually recommend putting functions as methods (eg m()) rather than using class fields when subclassing - it makes inheritance easier. Eg, if you used

class Class {
    m() {
        console.log('super')
    }
}

m would be on the super prototype, so the child class would be able to put m either on the child prototype or on the instance (with a class field) and it would overwrite the super's m either way.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320