Is JavaScript really a prototype-based language? In prototype-based programming, you create an object which has shared functionality (the prototype), and then create new objects by cloning that object. That's not how you implement shared functionality in JavaScript; in JavaScript, you implement shared functionality by delegating to another object. In other words, JavaScript objects work like Python, or Ruby, or Smalltalk (yes, unlike these languages JavaScript, until ES6, makes no language-level distinction between an object which is also a class, and an object which isn't a class, but that's just a matter of syntactic sugar).
The 'cloning' is abstract: it doesn't refer to an actual duplication. Typically code is delegated for performance, and data is copied or constructed. JS is prototypical.
You identify the key point: there is no distinction between classes and instances. Classes are first-class objects, that can inherit themselves, and so on, and so on. Some languages (like Python) find they need these extra levels and introduce 'meta-class'es, this is irrelevant in JS.
Also the last bit is why 'class' is a bad move in ES6. ES6 still makes no distinction between a class and a non-class. It still does not provide classes in the Classical inheritance mode. It is just syntactic sugar for deriving an object with prototypal inheritance. I can inherit a class from an instance, or classes from classes. All it does is bless the approach of using prototypes in ways that are recognizable from non-prototypal languages. The fact that most people will (incorrectly but understandably) assume the JS now has classes is why this is ill advised.
> You identify the key point: there is no distinction between classes and instances. Classes are first-class objects, that can inherit themselves, and so on, and so on.
Classes are first class objects in Python as well, and have their own inheritance hierarchy. (And so on, and so on.)
> Some languages (like Python) find they need these extra levels and introduce 'meta-class'es, this is irrelevant in JS.
JavaScript lacks metaclasses because it lacks the concept entirely… no? (Though perhaps you can take your FooClass and run it through a function, permuting it as desired, but then, you would still need to do that at every base-class's definition site.)
JavaScript programmers do opine often (in my opinion) that Javascript is "prototype -based", and not single-inheritance OOP. Yet an objects behavior in JS seems exactly that of Python; if I take an object, "obj", and access obj.some_attr, I:
1. In JS: look for the attribute on the object (getOwnProperty, essentially?)
In Py: look for the attribute on the object (in __dict__)
2. If not found, start
In JS: follow the prototype chain
In Py: follow the MRO
Python just gives me exceedingly better syntax to do it with, IMHO. (Which the new additions in the article help with — I'm referring to the article's first example, in good ole JS.) This is slightly different from Java and C++, which strictly separate the whole instance-data from class methods.
You can't inherit a class from an instance in python. Classes and instances of classes are distinct (though the semantics aren't equivalent, a class is described as an instance too, but of a metaclass, not of its parent classes). Both can only inherit from classes. Once you instantiate an instance, your inheritance is terminated.
I can derive any object from any other object in Javascript. An object can be treated as a class, a metaclass, or an instance. There is no language difference. That isn't just syntax, that is a deep part of the implementation and semantics.
Both languages are Turing complete, so of course one can build a system that does prototypal inheritance in Python, in fact it is rather simple, given Python's powerful delegation system. Just as you can create classes in Javascript. But there is a difference.
If you disagree, it may be worth you giving a definition of what you think prototypal inheritance is, as distinct from class-based inheritance.
> perhaps you can take your FooClass and run it through a function, permuting it as desired, but then, you would still need to do that at every base-class's definition site
You don't have FooClass in Javascript in the same sense. There is no metaclass in Javascript, because there is no concept of a class. Thus the restriction of the two-level ontology doesn't raise its head.
> follow the prototype chain, follow the MRO
This is the same for any class-based language. There is a delegation chain that goes from instance -> class -> parent class, etc.
So again, what do you think would make something prototypal? Do you think it is a meaningless term? Or just something fashionable to make Javascript sound important?
This isn't bashing Python, you can do plenty of stuff in python. But it does have a different model of object orientation to Javascript. Fortunately Python is flexible enough to subvert that if you need to. But that's not what the terms mean. It isn't the only language that is powerful enough to be able to implement alternate OO models.
"The 'cloning' is abstract: it doesn't refer to an actual duplication."
But it's not just abstract, it has real implications, because JavaScript objects share implementation of the delegated methods; that is, they behave just like objects in class-based languages.
Classes in Python, Smalltalk, etc, are also instances; it's just that these language has facilities to produce particular sorts of instances which are well-suited for being delegated to (and take some measures to enforce the use of these facilities), whereas traditionally in JavaScript conventions are used to distinguish those object which are delegated to, and those objects which are not. However, the distinction between objects which are delegated to (i.e., classes) and object which are not exists just as much in JavaScript as it does in with classical inheritance.
Of course all reuse is somewhat similar, but dividing things into separate categories (class, instance, metaclass) and enforcing rules on how they relate isn't a 'just', that's what class based inheritance is.
The issue of abstraction is that, you don't implement prototypal inheritance with copying. No language does. That's why delegation is such a core part of any prototypal inheritance. There are different points and ways that happen. But all inheritance is delegation, in practice.
Can you give an example of when a piece of code (i.e. not data) would be different if it were delegated vs copied?