And if you care,
- What about object copying / mixins?
- How does prototype work in TypeScript?
Why should I care about explicit private fields anyway, as I can always prefix it with underscore (_) just like Python, Dart or Go?
And if you care,
Why should I care about explicit private fields anyway, as I can always prefix it with underscore (_) just like Python, Dart or Go?
For further actions, you may consider blocking this person and/or reporting abuse
Josef Doctorovitz -
Chris Lojniewski -
Austin -
Truong Phung -
Top comments (4)
A couple of big differences that come to mind:
new
keyword when you want to instantiate it. This lets you do some rather interesting things, such as defining and instantiating a class as a single expression without having to bind the class to a name.Not sure I can touch on all the topics, going to ignore Typescript because I don't know it.
JS is an OOP language with prototype based inheritance which essentially means that the template to create a new object is another object. @lydiahallie wrote a great visual explanation on how that works: JavaScript Visualized: Prototypal Inheritance.
Java and Python also are object oriented but they implement a different paradigm, class based inheritance, which essentially means objects are printed from a class which acts as their template. Class based inheritance allows multiple inheritance, which Python offers.
Mixins are a good way to share behavior between objects, they could be viewed as a way to bypass the limitations of single class inheritance.
Not to say that multiple inheritance is the perfect solution, it can get complicated fast. The more I program the more I prefer to keep classes simple and rely on composition and dependency injection to create objects with the various bits of shared behavior.
Not everyone agrees, Ruby has mixins that in a real world app can quickly become similar to the issues that multiple inheritance has, the simplest being: "where does this method call I'm seeing in this line come from?". The same can happen with open classes. JS has a similar potential behavior with the fact that you can add methods to objects or their prototype at runtime.
None of this is inherently a problem, it's quite a perk of these dynamic languages, it becomes an issue if devs don't have a bit of "discipline" in how they extend behavior.
And with this we circle back to your other concern, encapsulation. My belief is that essentially Python is built with an unspoken contract in which the creator of the class trusts the consumer of the class because they are "both adults" and if the latter wants to delve into the private methods or private state it's their own responsibility.
So Python trusts devs, Java is on the opposite side of the spectrum in this. The agreement is that the consumer of the class shall always stick with the public interface of the class. The only drawback, which happened to me in the past, is that if the implementor made a mistake in the design of the class, the consumer essentially has to wait until the new version is available, whereas with Python you write code to bypass the mistake and wait for the new version to remove the patch.
Hope this was helpful to understand the different philosophies.
Hope this example is useful: Prototype based inheritance works by references to a single definition of class members (Class.prototype.someFunction) in the prototype class while in Java you create a copy of the members when inheriting from a class.
This has pros and cons on both sides and it would open the gates of hell discussing them now in-depth :-)
First to address TypeScript, there is no difference between TypeScript and JavaScript as far as classes are concerned. TypeScript supports "private" fields on classes, but it's more a suggestion (like the underscore prefix) than something enforced. In general the advantage of enforcing private fields, meaning that the field cannot be read or written to, is that you can rely on that field only changing in ways that your class specifies.
To understand the difference between class based and prototype based inheritance it's best to think of how we resolve a field/method.
In class based inheritance an object has fields that are specific to that instance and a class, the class has every field/method that is shared by all instances of this class. This includes all the fields on the classes parent class and the parent's class parent class etc. It's possible to do this because classes declare their parent classes, and those declarations don't change. Now to resolve a field on an object we first check the object, then the class, then we're done.
In prototype based inheritance an object has fields that are specific to that instance and a prototype, which is an object. Because a prototype is an object it has fields and a prototype. To resolve a field you first check if it's defined in the object, then check if it's defined in the prototype, then check the prototype's prototype, etc.
Given the nature of prototype inheritance it's potentially much slower than class based inheritance, however you get a trade-off in flexibility. For instance switching the prototype of an object after it's been created is trivial in JavaScript and effectively impossible in Java. You can also make changes arbitrarily in the prototype chain, which is powerful but also scary.
One note is that the ES6 classes have a syntax that makes then look a lot like classes in Java or Python but they are not. It's just a new syntax over the old functionality.
Not going to go into mixins, as others have explained they're a way to inherit from 2 different classes, how they're implemented is largely language specific.