Looking at modern JavaScript with classes, my understanding is that this is all syntactic sugar overlying the same prototype-based object model that is used prior to ECMAScript2015. I like working directly with prototype chains, but classes are definitely easier.
So it seems to me that, in JavaScript, programs are likely to all be specified according to a class-based syntax, but are likely to be executed according to the rules of prototype-objects. So there will always need to be some kind of conversion between how JavaScript is written, and how it is executed.
Regardless of how JavaScript is implemented via browsers and other engines, my question is:
From the perspective of writing a JavaScript engine, are there performance or other benefits in implementing an object-orientated language in terms of prototypal delegation rather than classes?
==== EDIT
A similar question (Hidden-class implementation of prototype-based language) has comments that suggest classes in the traditional sense are easier to implement at the compiler level because they can be laid out statically in memory (I think that is implied anyway), but that doesn't allow for dynamic structures such as JavaScript allows for. So it seems to me that it might be possible that prototypal delegation may be a good fit for implementing dynamic objects at the compiler level?
Another perspective is the object composition.
Consider this:
class X { method() {} }
class Y extends X { method2() {} }
const y = new Y();
Now, in "classical" OOP, y
would be an object, and it would have two methods, method
and method2
.
In prototypical (classic JavaScript) sense, y
is an object. The object has nothing by itself, but on its prototype, it has a method2
. Where is the first method
? Well, if you dig down the prototype's constructor, you'll see that it, also, has a prototype, with method
a part of it.
Copy-paste from Node REPL:
> class X { method() {} }
undefined
> class Y extends X { method2() {} }
undefined
> const y = new Y();
undefined
> y
Y {}
> y.prototype
undefined
> y.__proto__
Y {}
> y.__proto__.constructor
[Function: Y]
> y.__proto__.constructor.__proto__
[Function: X]
You need to be able to support people who monkey-patch prototypes of things:
> X.prototype.method = () => console.log('I am here now!');
[Function]
> y.method();
I am here now!
JavaScript is, in a way, compiled before execution. That's the "conversion" between how the language is written and how it's executed. Furthermore, as you said, many features of newer ES specs are in fact syntactic sugar.
Regardless of the way you declare the classes, they will eventually compile to a similar abstract syntax tree (correct me if I'm wrong). It could either be via an intermediate compiler like Babel, or directly by the executing implementation.
From that perspective, the main drawback of using the more abstract class definitions, from the perspective of writing a JavaScript engine, is that it needs to support a broader syntax.
The way to go, probably, is by reducing the class syntax to the more native prototypal syntax (intermediate compilation) - that's how I would consider implementing it. That would lead to a minor performance hit in the compilation phase.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With