5

Given two classes where I want to give the methods of one to another:

class a {}
class b {say() {console.log('hello')}}
var foo = new a();

How come this works:

a.prototype.say = b.prototype.say;
foo.say();    //'hello'

But this doesn't?

a.prototype = b.prototype;
foo.say();    //foo.say is not a function

To be clear, I'm not asking how to give one class's methods to another, but why prototype behaves like this.

Bonus question: what's the difference between defining a method inside a class block and defining it by directly assigning it to the prototype?

leinaD_natipaC
  • 4,299
  • 5
  • 21
  • 40

1 Answers1

6

The reason for this is that prototype on a class is a non-writable, non-configurable property:

class a {}
class b {say() {console.log('hello')}}

console.log(Object.getOwnPropertyDescriptor(a,'prototype'))

Non-writable means you can't reassign the property prototype and non-configurable means you can't change the property to make writable: true or delete the property.

The result is that this has no effect:

class a {}
class b {say() {console.log('hello')}}

a.prototype = b.prototype;
console.log(a.prototype === b.prototype)

But non-writable only means you can't change the value associate with the property a.prototype — it will always point to the same object — it doesn't mean that you can't add properties to that object. This is why you can still add a.prototype.say.

Mark
  • 90,562
  • 7
  • 108
  • 148
  • 2
    Also worth adding, this differs slightly from declaring `function a(){}` and `function b(){}` where `a.prototype = b.prototype` would actually change the prototype property. – zzzzBov Aug 23 '18 at 20:25
  • @zzzzBov That's pretty interesting. Are there other differences are there between a javascript "class" and a function? Even though they're supposed to be the same thing internally. – leinaD_natipaC Aug 24 '18 at 18:33
  • 1
    @leinaD_natipaC, they're not supposed to be the same thing. `class` is syntactic sugar for a bunch of common best-practices for creating constructors and prototypes, so it essentially adds a lot of boilerplate behind-the-scenes that can be duplicated if one chooses to do so. – zzzzBov Aug 24 '18 at 18:53
  • @zzzzBov That's the best description of js class vs function I've seen yet. I've searched for class vs function, [found a decent stackoverflow answer](https://stackoverflow.com/a/36102080/1730082). It seems like indeed the differences are mostly a bit of boilerplate and things you can and can't do inside the class definition. If I declared `a` as a function and *then* did `a.prototype = b.prototype`, can I expect `a` to behave exactly like `b` other than having a reassignable prototype? – leinaD_natipaC Aug 24 '18 at 19:31
  • 1
    @leinaD_natipaC simply assigning the prototype from `b` to `a` won't make the function `a` do the same thing as `b`. `a` and `b` will still be totally different functions with different behavior when called — in other words `a()` and `b()` might do totally different things. – Mark Aug 24 '18 at 19:34
  • @MarkMeyer Point taken, but I mean other than that, for example if `a` has no function body and `b` has no constructor, would they be the same thing then? Or would there be subtle distinctions like one having a mutable prototype vs the other one not? – leinaD_natipaC Aug 24 '18 at 22:21