| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| (Change the caloric expenditure of all animals when they move). | ||
| you should prefer composition over inheritance where you can. | ||
|
|
||
| Important thing is that JavaScript uses prototypal inheritance. It means new objects are instantiated by creating delegation links using OLOO (Objects Linking to Other Objects). Therfore you should be aware that JS does not offer real classes you may now from _Java_, _C#_ or other _object-oriented languages_. You may think: _"Hold on! There are `class` and `extends` keywords so I should be able to use classical inheritance."_. These keywords are _syntactic sugar_ and they are **not** introducing a new object-oriented inheritance model to the language (#[MDN: Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)). |
There was a problem hiding this comment.
Maybe the verb is omitted after '...JS does not offer real classes you may...'
Sorry, something went wrong.
There was a problem hiding this comment.
'Therfore' -> 'Therefore'
Sorry, something went wrong.
| this.email = email; | ||
| class Airplane { | ||
| constructor(initialState) { | ||
| const { name } = initialState |
There was a problem hiding this comment.
Other code examples use semicolons.
Sorry, something went wrong.
|
|
||
| // ... | ||
| getName() { | ||
| return `${this.name}` |
There was a problem hiding this comment.
Why not simply return this.name?
Sorry, something went wrong.
| // define base objects | ||
| const Airplane = { | ||
| getName() { | ||
| return `${this.name}`; |
There was a problem hiding this comment.
The same here as in the line 1537: why not simply return this.name;?
Sorry, something went wrong.
There was a problem hiding this comment.
I left it like this for the consistency with AirbusA380.getName method, but sure it's better to have shorter form here as the present one brings nothing and adds a few more characters.
Sorry, something went wrong.
|
Thanks for the great discussion in that Issue! The article from @ericelliott is a great one, and I do think we should reference it somehow about the nature of prototypal vs. classical inheritance in JavaScript. Meta-points here on the specifics of your PR: should we be trying to summarize an article about this or would just a simple link suffice? I think Eric's article and the other ones you link to provide a really great background, but something about summarizing them confuses me slightly when I take the point of view of a novice JS developer. There's a lot of technical terms that aren't thoroughly explained like OLOO. I had to go back to the article to remember the specifics of that. Eric's article is long because the topic is tough, I struggle to think of a concise way to summarize his awesome work, but I think simple high-level explanations of any topic are always possible. The latter half of your text about class being syntactic sugar also probably doesn't belong in the subsection about composition. We can definitely put that though in the preamble of the Classes section! Action items: let's discuss if we need to be providing a summary of these articles. If we determine we do need to, can we explain this as absolutely simply as possible? The explanation here is good if you already know the concepts, but it doesn't help novices fully. |
Sorry, something went wrong.
|
Thank you @ryanmcdermott for your review! The key point for me was to show how to compose different objects into prototype of the particular one. The other point was to encourage the developer to not use classes for inheritance (as JS does not provide real classes which are known from languages like C# or Java) and that is why I mentioned about class being syntactic sugar. A summary of the articles is there to briefly explain why the first example of code is bad and why the second one is better. Of course we can skip it if it may be confusing for some developers. Although we don't know if person reading this documentation has experience from other object-oriented languages or not. Therefore I believe the should some context provided on why we use factory function instead of class constructor. |
Sorry, something went wrong.
|
Why should you not use ES6 classes for classical inheritance? |
Sorry, something went wrong.
|
I think I have to completely disagree with this entire edit. You've taken out completely the discussion of why composition is more relevant vs inheritence and replaced it with an extremely biased blanket statement that "js inheritence is prototypal under the hood, therefore you should not use it." And then directed them off-site. Why does it matter if under the hood it's done using prototypes? What is the reason NOT to use it? You've only added material on explaining how it works but in my experience that isn't a reason in-of-itself to NOT use it. As with any language, it's a tool that you may use if it makes sense. The original text went into how to discern when such a scenario is present and how to quickly identify it. The original text also would have made sense with this addendum which displays how both can be used together: class EmployeeTaxData {
constructor(ssn, salary) {
this.ssn = ssn;
this.salary = salary;
}
// ...
}
class Person {
constructor(name, email) {
this.name = name;
this.email = email;
}
class Employee extends Person {
constructor(employeeId) {
this.employeeId = employeeId;
}
setTaxData(ssn, salary) {
this.taxData = new EmployeeTaxData(ssn, salary);
}
// ...
}It just kinda seems like you don't like the new ES6 feature personally. |
Sorry, something went wrong.
|
Hey @ProLoser, thanks for your point of view. I will try to justify mine. The section title is saying "Prefer composition over inheritance" so I was trying to show this kind of preference. Of course classes would be natural choice for developers who already code in Java, C# etc. And they don't always know that JS classes are not real ones. To sum up, I am not saying "you can't use classes in JS". But when you use them know their limitations well (plus know that composition is not restricted by these limitations). |
Sorry, something went wrong.
|
But why did you delete all the prior information that so clearly helped people understand when they should use it? For example I found this very helpful:
|
Sorry, something went wrong.
|
I think I may just fundamentally disagree with you on this one, because I personally think your example would be better off done using classes and inheritence syntax. I may be in the minority on this, so if there's a general majority that would agree with you I'll digress, but I'm curious if anyone else could chime in? I added an up/down vote to the original comment to perhaps see what other people thought. I do agree with a few points the article makes, but overall I don't think it's correct. For instance, exposing a public API for inheritence is bad, you shouldn't have to extend classes to use a library. But it's completely reasonable to extend classes in a library to extend the library (such as creating plugins). // CONSUMING THE LIBRARY WITH COMPOSITION:
const Telemetry = require('telemetry');
const telemetry = new Telemetry();
const ga = new Telemetry.GoogleAnalyticsPlugin();
// Composing the library
telemetry.debug(true);
telemetry.addUser({ /** currentUser **/ });
telemetry.setEnvironment('production');
// Composing the plugin
ga.setAppId('googleAnalyticsId');
ga.setProject('myProject');
telemetry.register(ga);
// EXTENDING THE LIBRARY WITH INHERITENCE:
const ComScore = require('comscore');
class ComScorePlugin extends Telemetry.BasePlugin {
constructor() {
super();
this.api = new ComScore();
}
dispatch(event) {
this.api.send(event);
}
}It's just not black and white. |
Sorry, something went wrong.
|
I almost feel this entire heading should be changed. People should make sure they identify when something should be a subclass vs a mixin. And another bullet that discusses explicit composeable code vs implicit convention-based code. Inheritence is just a tool which (like any tool in coding) can be used well or abused. |
Sorry, something went wrong.
|
I think each of our two has made his point. We have provided quite wide picture on the topic so I would be happy if more developer would leave their comments here. |
Sorry, something went wrong.
|
I think that the numbered list that @ProLoser points to should be kept and maybe expanded on, it's clear and easy to read for novices. The proposed additions by @kopacki contains too many links IMHO, a novice could be overwhelmed by having links to five different articles. (I also think Eric Elliott is a bit too extreme on hating classes 😁 ) A simple solution would be to summarize the content of every article, and I think adding some concept from the Clojure/Lisp world could help:
Also: classes are fine, the very bad thing to do is a chain of inheritance 5 levels deep. That's the devil! |
Sorry, something went wrong.
|
Perhaps a mention of the problems associated with class inheritance would be instructive. In particular:
Explain why composition is immune to these problems. @ProLoser Given enough time and evolution, all class taxonomies are wrong for new use-cases. For example, say you have a base-class Animal which implements .move() as described in the original examples. Not all animals move in the sense that snakes and monkeys move. Some are entirely incapable of locomotion. What happens when you need to add barnacles, corals, and sea anemones? You need to either change the base class, create a new base class that sessile animals can inherit from instead of the original Animal base-class. Both the old Animal class and the new sessile class can inherit from the new base-class, OR add special-case code for sessile animals everywhere any Animal instance is used to account for the differences between Animals and Sessile Animals. With composition, this problem does not exist. Adding new use-cases is simply a matter of composing different feature sets. |
Sorry, something went wrong.
|
@caesarsol I have good reasons to dislike class inheritance. I've seen it cause lots of expensive rewrites, and got a first-hand up-close look at how it can cause entire companies to fail. See "Inside the Dev Team Death Spiral". |
Sorry, something went wrong.
|
@ericelliott I absolutely agree with you! I've seen some mild cases of what you describe, and hated it. By the way I like your "Animal.move()" explanation very much, It's easy language and I'm sure would be very helpful for novices. The important thing is to foresee the future, not to just make things working now. |
Sorry, something went wrong.
|
Thanks @ericelliott for your incredible advice as always! My preference here is to just link out to articles with a one sentence description explaining it's important to understand prototypal inheritance. We should take the second example and put it in the preamble of the Classes section. I'll leave this PR in case you had the time to refactor this. Thanks all for contributing to this 😄 |
Sorry, something went wrong.
|
This section uses an explicit dependency EmployeeTaxData that violates the Dependency Inversion Principle. |
Sorry, something went wrong.
|
Closing due to inactivity, feel free to re-open! |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
This PR is regarding a discussion developers had on the issue #40.
As there was more positive reactions than negative ones I have decided to change the code example and description for the section to be more appropriate for JavaScript language and its features.
@ryanmcdermott if there is anything I can improve, fire away ;)