Some parts of this article are word-for–word copied from the MDN article on Inheritance and the prototype chain [0]
For example:
> While this is often considered to be one of JavaScript's weaknesses, the prototypal inheritance model is in fact more powerful than the classic model. It is, for example, fairly trivial to build a classic model on top of a prototypal model.
Although the MDN content is CC-licensed it behoves the author to be clearer about what is quotation and what is original content.
I wrote a paper on Classical OOP with ECMAScript 3/5 back in 2012 during my work on (the then-not-GNU) ease.js, which goes into quite a bit of detail on how prototypes work:
There are much nicer patterns available to program in an Object Oriented (or rather JavaScript) style. In the following gist I demonstrate (using a simple container library) private, protected and public members (including methods and properties) along with setting each object up for correct prototypal inheritance.
I would always start with this pattern for readability and maintainability sake and if performance becomes an issue switch to the `Obj.prototype.method = f()` form to avoid duplicating method instances.
This lets you specify the default iterator for an object. Lets you use `for of` on the object just like you can with arrays, maps, strings, sets, and typedarrays.
> The lookup time for properties that are high up on the prototype chain can have a negative impact on performance, and this may be significant in code where performance is critical. Additionally, trying to access nonexistent properties will always traverse the full prototype chain.
> The lookup time for properties that are high up on the prototype chain can have a negative impact on performance, and this may be significant in code where performance is critical. Additionally, trying to access nonexistent properties will always traverse the full prototype chain.
This makes no sense to me - surely every non-trivial JavaScript implementation has inline caching, and are not doing any kind of lookup at all in performance critical code?
The inheritance example is incomplete, as it should do `Editor.prototype.constructor = Editor;` after `Editor.prototype = ..`. Without this, `david.constructor` will be `User`, and a check like `david.constructor === Editor` will yield false. It's not a huge deal, since the class is usually checked with `instanceof`, but it shows that classes in ES5 are quite subtle.
The post seems to be missing composition. One way of doing it is like this:
const foo = {
someVal: true,
methodA() {},
methodB() {}
};
const bar = Object.assign({}, foo, {
methodC() {}
});
// bar now has all the properties of foo, plus methodC
And? Is IE really that common to support, even in enterprises, in 2017? In 2018? In 2036?
IE already requires twice the budget - no grid, no flex, no ES8, and maintaining polyfills for all these things (if they're possible) requires maintenance and slows down build time.
Even slow moving corporates have AD managed Chrome or Edge since half the products they purchase don't work with IE.
The only reason people keep supporting it is people keep making it a big deal if something doesn't work on an unmaintained browser. We have to draw the line somewhere.
Do you have someone who'll double your frontend budget, or a situation where IE users that have no other browsers available are so lucrative it's worth doubling your budget, to support them?
Frontend is grid, flex, and ES8. Supporting the older equivalents is expensive and it's web developers, caught in a culture of "it's good to support outdated browsers" who are paying the cost themselves, not clients.
It takes double the amount of effort (a conservative estimate) to use floats, clearfixes, overflow side effect hacks, wrappers and various other hacks for simple layout.
It takes double the amount of effort (a conservative estimate) for async.waterfall, endless .then() chaining, callback hell and various other techniques to work around lack of `await`
It takes double the amount of work (a conservative estimate) to do some kind of weird Flash thing because your browser doesn't support HTML5 clipboard.
...amongst a massive amount of other tech, all of which is supported on current browsers.
You don't see the cost since you're already paying it by avoiding current frontend techniques. But unless someone else is paying that cost you're giving away your time for free by supporting IE.
(Of course, you should support Edge amongst every other major browser)
> apparently doing a lot of googling finding the random stuff that IE11 doesn't quite support natively
Do you genuinely think the need to lay stuff out in a grid or manage callback workflows is exotic? Have you done any front end development?
> Your idea of IE11 support apparently revolves around people using the worst types of tech and coding practices
No. As written in the comment you're replying to, it revolves around the huge gulf between IE11 support for current tech when compared to Edge/Chrome/Safari/Firefox.
> "However, even where similar properties exist in the two versions of the specification, the capabilities of the older spec and implementation are very different to the new one. This means you can’t simply run Autoprefixer and consider the job done."
The only reason I mention clipboard (despite being less common) is we use it on our own site and the cost of implementing a second implementation in Flash fix is ridiculous.
I did a write up on my blog [1] that attempts to explain how prototypal inheritance works.
That said, whenever I teach OOP in JS I have found that a lot of developers do not understand the prototypal nature of JS.
Another source of confusion is the `this` keyword, how it works, and consequently how apply/call (which this article uses) affect `this' inside the function (or method).
1) if there are people who come back to using inheritance AFTER doing programming with typed systems that support typeclasses (like Haskell). If so, would you able to articulate why you think inheritance is still a superior pattern?
2) if there were any use cases that could be solved using inheritance that could not be solved more elegantly without it?
> if there were any use cases that could be solved using inheritance that could not be solved more elegantly without it?
There are behavior mixins, that you can look at Django views as an example. There are interface implementations when you want to have a few almost complete standard ones.
Both are cumbersome to implement on Haskell. If you make sure to not use any widely used class, you can hack them out of some sets of hierarchical type classes with possible some overlapping. But leaving half-done stuff at your API to be filled by client code is never pretty there.
What are typeclasses if not inheritance? As someone without a formal CS background, a type with multiple typeclasses sure looks to me like a class inheriting from multiple interfaces.
Overloading not inheritance. It is closer to the notion of interfaces in traditional OO languages, but it's a mistake to confuse interface implementation as inheritance.
This is a common problem with traditional OO languages: they conflate inheritance with subtyping, ie. "Y inherits the behaviour of X" is not always the same as "Y can be used anywhere an X can be used" (subtyping). C++ has "private inheritance" to separate these notions now, but it's a kludge from this initial design mistake.
So type classes use subtyping, but not inheritance. Interface implementation is also closer to subtyping than inheritance.
OOP classes (well, their instances) combine data and functionality into a single "thing" (well, object). Inheritance is nasty because you are not just composing structures of data or interfaces of functionality but both at the same time.
When you separate data from functionality into separate "things", composing things out of them becomes nicer.
I'm not a Haskell programmer, but AFAIK type classes contain functionality, NOT data (state).
Example of what I'm talking about: Clojure's Protocols.
Is this a typo, or intentional? If it is intentional, can someone explain the thought behind it?
Also, in some examples Medium (or the author's text editor) seems to have changed apostrophes and quotation marks, this makes the examples harder to try.
Why the “Yeah...JavaScript...”? The inline || is an incredibly common and useful feature in many languages. Also Op was just talking about the plural/singular difference.
You're right that we might use "short-circuiting" (AKA lazy) `||` in many languages to use a default value, but it doesn't usually work for variables.
For example, in Python:
>>> foo or "default"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
In Javascript, variables are either bound (e.g. with `var`, as a function argument, etc.) or else they're treated as properties of the `window` object (behaving effectively as globals).
This is very unusual, and can be thought of as mixing "data" with "code": the `window` object acts like a reified version of (global) binding environment, which in most other languages is implicit. This has implications for things like the usual distinction between bound and free variables (since we can imperatively add fields to `window` at any point), and hence for things like alpha-equivalence.
It will work for `foo = None`. It is just that undefined vars in Python are an error in a different class from a missing value.
For some reason, the short-circuiting is more used on languages where undefined vars is in the same class of missing values. But that reason is not obvious to me. Python in particular has an odd mixing of quasi-static and dynamic errors that works unreasonably well but does not accept this construction.
Here the variable `foo` is 'just doing its job' and can be simplified away to get:
None or "default"
This shows that variables aren't involved here: `or` is just an operation on data (in this case `None` and `"default"`), just like `+` or ``.
> It is just that undefined vars in Python are an error in a different class from a missing value.
Exactly, and I think that's a perfectly reasonable justifaction for disparaging Javascript (along with bash, PHP and anything else which has this similar behaviour).
In fact, as I said above, Javascript doesn't even have a notion of "undefined variable", since variables will be looked up in the `window` object if they're not locally bound, and hence what looks* like an undefined variable is actually (according to Javascript's semantics) a missing value (a missing property of the `window` object).
> Python in particular has an odd mixing of quasi-static and dynamic errors that works unreasonably well but does not accept this construction.
I'm not sure what you mean here. As far as I can tell, there are two ways to think about errors in Python:
- From one perspective, all Python errors are dynamic, since they happen at run time when we attempt to interpret the offending code. Some of these errors happen when/if we interpret an `import` statement, some happen when a more localised expression/statement is encountered.
- A different perspective is that Python doesn't actually have a concept of errors at all. There are values available in the language which are called "errors", but they're not really errors, in the same way that `myError = "hello"` isn't actually an error (it's a string, which might represent an error but it isn't a distinguished category of things; it's just a value). Since it's semantically meaningful to perform calculations involving these values (often, but not necessarily, with the control-flow statements `try`, `except` and `raise` (which is just another form of `yield`)) they're not "errors" in the same way that, say, a segfault or a compiler error is (which Python doesn't, or shouldn't, have).
For example, here's a perfectly valid (although inadvisable) way of defining `hello world` in Python:
$ cat x.py
def say_hello():
try:
foo()
print "goodbye"
except:
print "hello"
def foo():
i_am_undefined
$ python
Python 2.7.13 (default, Dec 17 2016, 20:05:07)
[GCC 5.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import x
>>> x.say_hello()
hello
>>>
Its not the inline ||. It is the need for such a pattern in JS due to terrible scoping rules, such that it is very easy for a variable definition to leak somewhere else and you really don't want to crush it.
I love prototypical inheritence. I find it much tidier and easier to understand than the class based inheritence in other C family languages.
I really wish that class syntax did not become a thing in Javascript. IMO that was the biggest mistake made so far in it's development. Just call a spade a spade instead of piling another level of abstraction on top.
It added a bunch of other useful things, like getters/setters, constructor function, simpler method descriptions, etc.
I don't have a problem with the class title, after all it describes a class of things. When you extend something you really extend the scope of your class, so I still find it adequate.
There are differences in OO behavior between Java and C# but I haven't heard people complaining about naming classes classes.
I know that and probably that's why people feel a bit annoyed by the Class keyword. However it's really close to what classes should represent. https://en.wikipedia.org/wiki/Class_(computer_programming) first two paragraph matches the JS use case well.
> Javascript objects are not contractually obligated to have the state and behavior of a 'class'.
I don't know what you mean by "contractually obligated", but if I instantiate a class in JS then it will have a state and behavior I defined in that class. If your problem is that if I change that class later, then the instances will change as well, then yes, it works like that. Calling something a class in my mind is not strictly limited to classical OO, it's just a loose concept different languages implement differently.
For example:
> While this is often considered to be one of JavaScript's weaknesses, the prototypal inheritance model is in fact more powerful than the classic model. It is, for example, fairly trivial to build a classic model on top of a prototypal model.
Although the MDN content is CC-licensed it behoves the author to be clearer about what is quotation and what is original content.
[0]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inhe...