I think if you ever have to interact with prototypes directly with JavaScript, it's by and large a smell: it's fraught with pitfalls (the notorious for...in issue of Prototype.js from years ago), more syntactically tedious than using ES classes, and is too dynamic to play nicely with static typing in a lot of cases. The model is historically interesting but probably not what you should be dealing with in 2023.
Seconding. Doing anything "interesting" with the distinctive features of the prototypal model is practically always a bad idea. Unless there's some much-better implementation out there in another language, I'd regard the whole model as basically a dead end. One giant obfuscatory foot-gun with nothing particularly necessary it enables that can't be accomplished well-enough with some other model.
The thing is, you can't really avoid them. It's an important part of the language, and not understanding my bring you pain.
In mid-late-2000s when the first idea of adding classes to the syntax came up, even Microsoft eventually said: nah, it's a bad idea. It's grafting incompatible concepts onto a language that doesn't need them.
And then Google in their "wisdom" went and forced classes onto the language. Take a guess why you need this for methods to work the way you expect them:
I don't think you need prototypes to understand this, though it is maybe a consequence of them. If you remember that functions are just always free functions and calling them without a context means `this` has no context (unless they are bound or declared with a fat arrow), then I think that gets you 100% of the way there.
`this`, of course, is a whole other bag of worms :(
> I don't think you need prototypes to understand this, though it is maybe a consequence of them.
You do indeed need to understand prototypes to explain this behavior. "Free functions" doesn't really make sense, because it obviates the need for classes.
> Take a guess why you need this for methods to work the way you expect them
This is not Google's fault. It is the fault of Java developers. They expect everything to work like Java. They expect to find Java APIs everywhere.
I have never written classes like that. In fact, if I were to see a method being used in the way you are insinuating I would believe to have found a bug.
I strongly dislike class-based object orientation in general. But I'm glad we do not have to deal with dozens of ways to do OOP in JavaScript anymore.
It quite literally is. In there desire to push web components they also pushed quite a few (often questionable) solutions. See 17:59 here: https://youtu.be/y-8Lmg5Gobw
> But I'm glad we do not have to deal with dozens of ways to do OOP in JavaScript anymore.
There never were "dozens of ways". There always was only one: prototype based. And now there's this weird contraption on top that pretends its classes from C++-like languages (C++, Java, C# etc.) but is not.
Part of my gripe when React moved to class syntax was the loss of auto-binding, not that its an inherent part of prototypes or anything but I didn't get why that should be sacrificed for 'a standard', unless there was stuff I'd forgotten were important gains
> was the loss of auto-binding, not that its an inherent part of prototypes
It is, because classes are a thin wrapper over prototypes, but the whole "classic C++-like" class shenanigans translate very poorly to Javascript. And yet, with maddening bravery browsers have spent 10 years trying to make them work in some capacity (and don't get me started on the whole private members thing, or the autobind proposals, or...)
this statement is naive. there are legacy codebases that dont use build systems or transpilers, still uses ES5 syntax. the minifier is a make file that concatenates the js files.
its pitfalls should be understood and avoided instead of being afraid of JS prototypes
...which is almost always true for any forward-looking prescription. If someone says "you don't need var anymore, just let and const", of course you can append to that conversation and say "isn't that so naive? what about codebases where you don't have a choice? You should understand var."
I feel like the people who are in that situation know who they are. The rest of the world benefits from knowing what subset of the ecosystem they want to work with, as opposed to "you should know everything", which is the most inclusive and the least useful statement.
Reminds me a lot of how the common lisp object system evolved (or even C++). You start with an extension to the language, then it gets formalised, then it becomes something new(ish). Bit like evolution continuing to come up with the same answers in different evolutionary trees.
Bit of a shame that the javascript guys didn't look at CLOS it might have been quite easy to port across. They do seem to share some implementation details (like the way which function is the right one to run).
I'm a very experienced programmer but I try to avoid Javascript because any description of how it works includes passages like this one from TFA:
"This is because a property declared in Rect.prototype is not available in Rect itself but only in objects created with new Rect. In this sense, Rect.prototype serves as a kind of “template” for objects produced by new Rect. As you can see, we are dealing with two different but quite similar concepts."
Ohhhh...Kaaaaay.
One tip I've learned when I have to use Javascript: Avoid 'this' whenever possible. There are 14 things 'this' can mean in Javascript, and whichever one it does mean depends on both the static context and the dynamic context (and possibly the phase of the moon). In most cases it's possible to avoid using 'this' by adding explicit variables. But I'm not sure it's always possible to avoid it. Yikes.
Oh, and I'm never quite sure when it's a good idea to use 'new'. TFA addresses 'new' a little bit. At least it's not as big a can of worms as 'this'.
> This is because a property declared in Rect.prototype is not available in Rect itself but only in objects created with new Rect.
This isn't really any different to other languages. The equivalent for Java would be "(non-static) properties are not available directly on the class but only on instances of that class"
> One tip I've learned when I have to use Javascript: Avoid 'this' whenever possible.
Arrow functions help a lot with this. Their 'this' cannot be overriden and thus is determined by static context only. With regular functions, the rule is that it depends how their called:
- If you call "foo.bar()" then "this" will be "foo".
- But if you do "var baz = foo.bar" then call "baz()", then "this" will be undefined.
- You can always set "this" explicitly by call a function with `.call`. In either "foo.bar.call(quz)" or "baz.call(qux)", "this" will be "qux".
> Oh, and I'm never quite sure when it's a good idea to use 'new'. TFA addresses 'new' a little bit. At least it's not as big a can of worms as 'this'.
Use "new" if and only if you're instantiating a class (whether that's written with the new class syntax or the older prototype syntax). That's it. It's possible to make a constructor work without "new", but it's an extra line of code and is generally considered non-idiomatic.