Modern Language Feature Confusion in ES6, prototypes vs OO

Reflection on This Opinion - more rant, many execrated points

Similar Opinion HERE. - but more conscious, less rant

This article is actually great if you want to test your JavaScript knowledge's depth.

I think the author's opinion is based on him preferring languages that have a much more opinionated and fix structure, like Java.

I have heard from advanced C++ developers that if you want to create maintainable code, you do not use 90% of the language's features. Which might be similar to this JS's case as it has developed over time from being a cute wonky script language to be what it is today. Language is just a way of expression.

In every programming language, the designers of the language create a level of abstraction above the metal exposing it's capabilities to the developer. On top of that, people create libraries, extensions, that are written using the language as a base to build up on.

People developing JS have decided to go with the Prototypical inheritance model, as it's simple, efficient and flexible.

What came later was that as more and more complex codes were written on this language, people started implementing the same things in odd ways. If a dev comes from OO languages like Java, they inevitably will start looking for these language features. Instead of letting them hacking around, the JS developers decided to go and formalize this: how to extend the prototypical inheritance model into supporting Object Oriented inheritance and notation in a standardized way, so people coming from these other languages will find it more familiar, and not everyone will do whatever parts they understand - a 1000 different ways.

I think it's a good decision, and given the variety I've already seen, how people tried to "hack" these features into existing JS codebases, it's much better to have a standard that's backward compatible, than just looking the other way. It creates better quality of code, makes it easier to transition from other languages.

Now there is a way to do it right, and standard, even if you do not understand the prototype inheritance concept.

Justen demonstrates that this is a problem:

function Proto() {
this.name = 'Proto'
return this;
}

Proto.prototype.getName = function() {
return this.name
}

class MyClass extends Proto {
constructor() {
super()
this.name = 'MyClass'inheritence
}
}

const instance = new MyClass()

console.log(instance.getName())

Proto.prototype.getName = function() { return 'Overridden in Proto' }

console.log(instance.getName())

MyClass.prototype.getName = function() { return 'Overridden in MyClass' }

console.log(instance.getName())

instance.getName = function() { return 'Overridden in instance' }

console.log(instance.getName())

I disagree. You just do not do this. No one should do this. Ever.

You pick one. Either ES5, then you do not use inheritance, or either ES6, then you do not use prototype.

He even says at one point under one of the code blocks:

Note: You'd almost never write code like this in real life—it's terrible practice—but it demonstrates the principle succinctly.

Not Almost. Really Never. It's there for compatibility, so things do not happen backwards like in case of Python 2 vs 3: half of the internet does not break due to this.

The key takeaway is that prototypes don’t define a type; they are themselves instances and they’re mutable at runtime, with all that implies and entails.

Precisely. As a JS developer, you should be aware of this, hence you should NEVER tamper with prototypes manually in ES6. There is no valid reason for you to do that.

If you want types, you use TypeScript, and you should, as static checking is a good thing.

Which Do Experienced JavaScript Developers Prefer—Prototypes or Classes?

function secretFactory() {
const secret = "Favor composition over inheritance, `new` is considered harmful, and the end is near!"
const spillTheBeans = () => console.log(secret)

return {
spillTheBeans
}
}

const leaker = secretFactory()
leaker.spillTheBeans()

FALSE. This is one way to do it. Some libraries like KnockoutJS follow this pattern, yes. But it does not mean that the new features are bad. In this case, you have to be aware of the JS's scoping mechanism, why I find the class notation more intuitive, as it's much more similar to Java's. (I'm generally doing full-stack, but more on the JS front)

For one thing, you can destructure it because you don’t have to worry about the context of this:

function secretFactory() {
const secret = "Favor composition over inheritance, `new` is considered harmful, and the end is near!"
const spillTheBeans = () => console.log(secret)

return {
spillTheBeans
}
}

const leaker = secretFactory()
leaker.spillTheBeans()
const { spillTheBeans } = secretFactory()

spillTheBeans() // Favor composition over inheritance, (...)

Yes, composition pattern has it's advantages, but you'd never want to expose a class's internal variables like this. It's just a different paradigm.

function spyFactory(infiltrationTarget) {
return {
exfiltrate: infiltrationTarget.spillTheBeans
}
}

const blackHat = spyFactory(leaker)

blackHat.exfiltrate() // Favor composition over inheritance, (...)

console.log(blackHat.infiltrationTarget) // undefined (looks like we got away with it)

Clients of blackHat don’t have to worry about where exfiltrate came from, and spyFactory doesn’t have to mess around with Function::bind context juggling or deeply nested properties. Mind you, we don’t have to worry much about this in simple synchronous procedural code, but it causes all kinds of problems in asynchronous code that are better off avoided.

Very no. He demonstrates very bad practices to how to write JS. No sane person would ever create something that uses spyFactory.

A very good argument of his is

Would you use a hammer labeled “screwdriver” to drive a screw, when your toolbox had as actual screwdriver sitting right next to it?"

Which I believe is partly true only, as there are many different screwdrivers to drive that screw in, and some are more familiar with the green over the yellow one. It's a people question, not a coding one.

Brought this example with polymer's core library as a serious scary wizarding: that's a very special UI lib, that's dealing with a very different abstraction than an average JS dev has to... That's next level code using a handful of different patterns, and probably making some design decisions based on devs that came from very different backgrounds. There is a reason that lib is no-longer alive.

many popular front-end frameworks encourage its use and you should probably avoid writing weird non-standard code on principle alone.

I think this is a key statement here.

As more people are actually familiar with the OO pattern, do not force them to hack their way to it, provide a standard that actually does it the right way. That way people will not try to hack everything together 1000 different ways depending on their level understanding these rather complex and abstract patterns.

Instead, provide "the right way". Practical. Clean.

JS does it smart.

"The reasonable man adapts himself to the world: the unreasonable one persists in trying to adapt the world to himself. Therefore, all progress depends on the unreasonable man."

Man and Superman (1903): Maxims for Revolutionists, George Bernard Shaw