9 ms·
JavaScript: prototype vs. class
- jdeisenberg 9y agoI do not know if anything has changed since this discussion: https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/apA.md https://github.com/getify/You-Dont-Know-JS/blob/master/this%... but it seems that classes may not always be the answer.
- stupidcar 9y agoA lot of these examples seem rather contrived, and the whole appendix has a very FUDy feel to it. It seems like the author didn't like classes in JS, and set-out to come up with some examples to justify their dislike, rather than coming to that conclusion through actually encountering these problems in the real world. Something not helped by the weaselly tone, constantly implying that it's just raising concerns, when it's clearly been written by somebody with an extremely strong anti-classes mindset. As a simple way to define a reusable bundle of behaviour of logic, or to construct simply base-class -> specialisation inheritance hierarchy, JS classes work fine.
- Can_Not 9y agoTotally agree, checkout this example: > If you change/replace a method (on purpose or by accident) on the parent "class", the child "class" and/or instances will still be "affected" I knew when reading this line exactly what the author was about to do to mislead the unsuspecting user. Directly edit the prototype and feign surprise. The prototype is representative of the class itself, basically a default of all properties for that class. The correct (and obvious) way to override a class method for only one member of the class is to assign a new function on the property directly, not into the prototype's version of the property. Class definitions being mutated in an application is extremely uncommon. This is like putting your hand on a hot stovetop and then complaining that you burnt yourself.
- chris_wot 9y agoWhat, that's all it does? Stop someone from accidentally not using the new keyword? I'm not dissing it, that's great it does this. But I'm a bit surprised (and happy!) that this is all it does.
- chatmasta 9y agoWell, it also removes the need to tediously write prototype definitions...
- lucideer 9y agoExactly. It's surprisingly well thought through. Literally the best of both worlds: it's not some entirely separate "new way" that's incompatible with the old way and adds significant implementation baggage, but still makes the most common in-the-wild use of prototypes shorter, while also being intuitive for non-Javascripters, and still allowing experienced old-school Javascripters access to the same prototype chain they're used to.
- dmitriid 9y agoThey are well thought through until you add class fields into the mix (already at stage three) and the actual real world usage (where you have to do this.method.bind(this) for every methods used in per-instance callbacks)
- lucideer 9y agoAgree on class fields but there's high demand. I haven't examined the exact detail but it seems hard to please both sides here. Not sure what the best way forward is. On .bind(this), that's exactly what I meant by keeping the old system. "Fixing" that magically would have required underlying changes. That said, since you brought up class fields and bind in the same post, there's always: class Dog { bark() { console.log('Bark!'); } eat = (food) => console.log('Munch'); } feedDog(dog.eat);
- hashkb 9y agoThis doesn't do a good job of supporting its thesis. The new syntax does in fact allow most devs who understand "traditional" class based inheritance to use JS the way they expect. The fact that it's implemented in JS is both good and also OK to ignore for most devs.
- hajile 9y agoIn my experience, the class syntax has been more bad than good. Devs with experience in other languages simply start writing classical OOP code without realizing the ramifications of what they are doing. Unless you are creating thousands of rigidly structured instances (never adding/removing properties or changing property types), you are almost always going to be better off using the factory pattern instead where you get other benefits like no `new` and real privacy.
- untog 9y ago> the ramifications of what they are doing Which are? And why is "no new" a benefit? IMO it's a good thing that you can write JS in the way you write other languages. It makes it a lot easier for developers to get going with it.
- tonyedgecombe 9y agoI'm trying to learn modern JavaScript at the moment, as well as getting to grips with prototypes I now have additional class syntax to learn and understand. I've gone from learning one way of doing things to two, how is that easier to get going with?
- always_good 9y agoBecause now there's one way instead of everyone bringing their own createClass/inherits implementation. Also, prototypical classes like `function User` are now rare in my experience going forward.
- 9y ago
- ahulab 9y agoanother interesting way to understand JS classes is to look at the transpiled Babel output of a class definition and extension [like this](https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=MYGwhgzhAEBiD29oG8BQBIY8B2EAuATgK7B7wEAUAlCqtPdOngBYCWEAdGNALzQDkYfnQYBfESPQBbAJ4AzItmDVaDRgQCmeIgWwDZCpcLXjxqUJBgAhMAWgaAHng3YAJjARJkooA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=false&presets=es2015%2Ces2016%2Ces2017%2Clatest%2Creact%2Cstage-0%2Cstage-1%2Cstage-2%2Cstage-3%2Ces2015-loose&prettier=false&targets=&version=6.26.0&envVersion= https://babeljs.io/repl/#?babili=false&browsers=&build=&buil...)
- drinchev 9y agoWhen comparing ES2015 and how it was before. I usually take the babel playground [1] and see what the closest alternative would be. For a simple es2015 it looks a bit more complicated than the prototype extension [2]. class Dog { bark() { console.log( "Bark!" ); } } Compiles to : "use strict"; var _createClass = (function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Dog = (function() { function Dog() { _classCallCheck(this, Dog); } _createClass(Dog, [ { key: "bark", value: function bark() { console.log("Bark!"); } } ]); return Dog; })(); 1 : https://babeljs.io/repl/ https://babeljs.io/repl/ 2 : https://babeljs.io/repl/#?babili=false&browsers=&build=&builtIns=false&code_lz=MYGwhgzhAEAiD2BzaBvAUNaAjMAnA1gBQCUq0w8AdhPCAKYB0ISh0ARAEJ74CEb0xANzQAvmhFA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&lineWrap=false&presets=es2015%2Ces2016%2Creact%2Cstage-2&prettier=true&targets=&version=6.26.0&envVersion= https://babeljs.io/repl/#?babili=false&browsers=&build=&buil...
- masklinn 9y ago> For a simple es2015 it looks a bit more complicated than the prototype extension [2]. That's because it provides somewhat different features and Babel apparently attempts to replicate them properly. For instance "class" methods are non-enumerable by default, whereas "prototype" methods — being bog-standard properties — are.
- Parsyval 9y agoSince I work with Typescript, I do the same with the TS playground, it's really usefull to learn that kind of stuff.
- mikegerwitz 9y agoThose interested in how prototypes and classical inheritance relate (and don't) may be interested in work I did on GNU ease.js, which works with ECMAScript 3+. I have since extended it to support Scala-like traits. https://www.gnu.org/software/easejs/manual/easejs.html#Implementation-Details https://www.gnu.org/software/easejs/manual/easejs.html#Imple... I also wrote a paper on some of the concepts: https://mikegerwitz.com/papers/coope/coope.pdf https://mikegerwitz.com/papers/coope/coope.pdf The `class' keyword in JS still leaves much to be desired; it's just syntatic sugar around the prototype model. There's nothing wrong with that model---it's just important to understand how it differs from what OOP developers traditionally expect.
- nostalgeek 9y ago> it's just syntatic sugar around the prototype model. No it allows "super" late binding, something you cannot do with functions and prototypes. It's not just "sugar".
- lucisferre 9y agoWhile it is good to understand how Javascript prototype inheritance works, I find it is best avoided , along with `this` and `class` syntactic sugar). It is rarely required and most anything can be achieved with very basic JS objects and functions which are simpler to work with, easier to reason about and easier to write tests for.
- watty 9y agoI disagree - not adapting to the latest language paradigms because you find it more difficult is code smell.
- mjburgess 9y agoCode smell describes code which has incurred technical debts among other things. People do not have it. The "latest language paradigms" in this case are JavaScript adopting a style of programming 40+ years old (Simula) -- despite its originating model being younger (self). Adopting paradigms because they are "recent additions" to a language is cargo cultism. Paradigms come with idioms that suit some problems better than others, and have all sorts of trade-offs and considerations. Inheritance is now widely regarded as a design approach, overall, best avoided. "easy to reason about" =/= hard to understand. The ease of reasoning about something is a feature of how complicated it makes it (partly, its incidental complexity). It's not to do with how dumb you are. Inhertiance, for example, creates systems that are often needlessly hard to reason about.
- hajile 9y agoWe had a whole generation of class-heavy inheritance-ridden frameworks and applications. It's bad enough in static languages. In JS, it quickly becomes an unmaintainable pile of spaghetti. Object literals with small doses (read: 1-2 levels at most) can be good. Going further risks multi-level breakage because properties are bound to get added/removed across the codebase over time due to the dynamic nature of JS.
- plurgid 9y agoYeah I dunno. There's like at least 3 or 4 different ways of constructing "classes" without the Class keyword. Frankly, that's a mess. I get that each has it's own advantages etc, but I don't WANT to figure out some hipster's clever new way of managing inheritance chains. I want to use the supported method of creating classes within the language. I prefer usage of the "Class" keyword because no matter how the language changes from here on out, it's a pretty safe bet that "Class" is going to always be the rightest way to do it, and the one that everyone else will understand.
- callesgg 9y agoI like the way javascript does inheritance, it is very convenient most of the times. But whenever i start looking on the details of how it actually works, I feel like my brain is experiencing a bunch of small seizures.
- kyberias 9y agoThis article didn't demonstrate any risks involved in using 'class' in Javascript by devs familiar with other OOP languages. What exactly is the non-common feature in Javascript OOP that exists in other OOP languages and therefore poses such a risk that makes developes make "a lot of mistakes"? It's not messing around with prototypes, since those devs don't understand that any way. Sounds like Javascript dev who is pissed because the language evolves and his prototype-hack-knowledge becomes more and more obsolete.