When you have this:
class Example {
method() {
}
}
const e1 = new Example();
const e2 = new Example();
You have one copy of the method
function, not two. It's on the object that both e1
and e2
use as their prototype, like this:
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| |
\ +−−−−−−−−−−−−+ |
Example−−+−>| (function) | |
+−−−−−−−−−−−−+ +−−−−−−−−−−−−−+ |
| prototype |−−−−−−+−+−>| (object) | |
+−−−−−−−−−−−−+ / / +−−−−−−−−−−−−−+ |
| | | constructor |−−+ +−−−−−−−−−−−−−−−−+
| | | method |−−−−>| (function) |
| | +−−−−−−−−−−−−−+ +−−−−−−−−−−−−−−−−+
| | | name: "method" |
+−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−−−−+
e1−−−−−−−−−>| (object) | | |
+−−−−−−−−−−−−−−−+ | |
| [[Prototype]] |−−+ |
+−−−−−−−−−−−−−−−+ |
|
+−−−−−−−−−−−−−−−+ |
e2−−−−−−−−−>| (object) | |
+−−−−−−−−−−−−−−−+ |
| [[Prototype]] |−−−−+
+−−−−−−−−−−−−−−−+
But when you do this:
class Example {
constructor() {
this.method = () => { };
}
}
const e1 = new Example();
const e2 = new Example();
or this:
class Example {
method = () => { };
}
const e1 = new Example();
const e2 = new Example();
You have two copies of the method
function, one for e1
and one for e2
, like this:
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| |
\ +−−−−−−−−−−−−+ |
Example−−+−>| (function) | |
+−−−−−−−−−−−−+ +−−−−−−−−−−−−−+ |
| prototype |−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−+−>| (object) | |
+−−−−−−−−−−−−+ / / +−−−−−−−−−−−−−+ |
| | | constructor |−−+
+−−−−−−−−−−−−−−−+ | | +−−−−−−−−−−−−−+
e1−−−−−−−−−>| (object) | | |
+−−−−−−−−−−−−−−−+ | |
| [[Prototype]] |−−−−−−−−−−−−−−−−−−−−−−−−−−−+ |
| method |−−+ |
+−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+ |
+−−−−>| (function) | |
+−−−−−−−−−−−−−−−−+ |
+−−−−−−−−−−−−−−−+ | name: "method" | |
e2−−−−−−−−−>| (object) | +−−−−−−−−−−−−−−−−+ |
+−−−−−−−−−−−−−−−+ |
| [[Prototype]] |−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
| method |−−+
+−−−−−−−−−−−−−−−+ | +−−−−−−−−−−−−−−−−+
+−−−−>| (function) |
+−−−−−−−−−−−−−−−−+
| name: "method" |
+−−−−−−−−−−−−−−−−+
Any decent JavaScript engine will share the code amongst those function instances, but the function instances themselves must be distinct, because they close over different contexts (the context of the call to the constructor where they're created). (The function objects themselves don't need to be very big, particularly in a thoroughly-optimized engine. If you look at the internal slots a function must have [in effect; engines can optimized provided they behave as described by the spec], only [[Environment]]
varies between them.)
The advantage to the arrow functions created per-instance is you don't have to worry about what this
they're called with, because they ignore it; instead, they use the this
they close over (which will refer to the instance created when they were created), which can be handy for callbacks.
The advantage to the method is that it's shared, and (in highly-dynamic environments) if it's replaced on the prototype with a different implementation, e1
and e2
will use that updated implementation. (That's a rare edge case.)