
Object-oriented Programming in vanilla JavaScript - 1bytebeta
https://medium.com/@shlominissan/object-oriented-programming-in-vanilla-javascript-f3945b15f08a
======
Veen
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.

[0]: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Inhe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

------
mikegerwitz
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:

[https://mikegerwitz.com/papers/coope/coope.pdf](https://mikegerwitz.com/papers/coope/coope.pdf)

I also provide a lot of information on the implementation of GNU ease.js here:

[https://www.gnu.org/software/easejs/manual/Implementation-
De...](https://www.gnu.org/software/easejs/manual/Implementation-
Details.html#Implementation-Details)

~~~
sametmax
It's a good paper, but it really needs a more accessible, much less dense,
layout, and some syntax highlighting.

------
kalekold
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.

[https://gist.github.com/nomad-
software/78be4f1dd429325c5ebed...](https://gist.github.com/nomad-
software/78be4f1dd429325c5ebede48237f5120)

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.

~~~
tiuPapa
Why symbol.iterator?

~~~
spmurrayzzz
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.

------
amelius
Mozilla has a nice writeup:

[https://developer.mozilla.org/nl/docs/Web/JavaScript/Inherit...](https://developer.mozilla.org/nl/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

But note:

> 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.

~~~
chrisseaton
> 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?

------
illlogic2
Why not [https://eloquentjavascript.net/](https://eloquentjavascript.net/)?
The 2nd edition is still good from my understanding.

The author is also trying to update it and is close to their funding goal:
[https://eloquentjavascript.net/3rd_edition/](https://eloquentjavascript.net/3rd_edition/)

~~~
hood_syntax
Thanks for bringing this up, I didn't know they were looking for funding for a
third edition.

------
BenoitEssiambre
On this theme of the joys of plain old unencumbered javascript, I did one
titled:

Callback Heaven: Continuation Passing Style Patterns for JavaScript:

[https://medium.com/@b.essiambre/continuation-passing-
style-p...](https://medium.com/@b.essiambre/continuation-passing-style-
patterns-for-javascript-5528449d3070)

------
oblosys
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.

------
nailer
Just use `class`: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Classes)

If, for some reason, you need to support old browsers, you can transpile to
ES5, ES3, stone tablets and similar.

~~~
amatera
Classes are just syntactic sugar. They use prototype under the hood. So maybe
it's good to know what happen there.

------
z3t4

       var MyApp = MyApp || {};
    

This is an anti-pattern, only use it for polyfilling. Use local variable
scope!

~~~
vilmosi
I used this pattern when you had multiple files extending the same global
state. For example when lazy loading based on the page you're on.

It can definitely be overused, which is probably why it's an anti pattern, but
it had it's uses before webpack.

~~~
z3t4
Here's how I do it:

    
    
      "use strict";
      if(window.hasOwnProperty("MyApp")) throw new Error("MyApp already exist!");
      var MyApp = {};
    

But I recommend using a module loader.

~~~
vilmosi
That's not exactly the same code as above but yeah, use module loaders.

------
ChrisSD
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

~~~
test1235
Unfortunately, Object.assign() isn't supported by any IE except Edge.

[https://docs.microsoft.com/en-
us/scripting/javascript/refere...](https://docs.microsoft.com/en-
us/scripting/javascript/reference/object-assign-function-object-javascript)

~~~
nailer
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.

~~~
nicoburns
Short answer is yes. Typically the requirement is IE 10 or 11 now, rather than
6 or 8 as it used to be. So progress is being made.

~~~
nailer
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.

~~~
strictnein
It doesn't take double the budget to support IE and the vast majority of
frontend work isn't in grid, flex, and ES8.

~~~
nailer
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)

~~~
askmike
I don't know any website that is using stuff like `await` in the frontend
without transpiling it down via babel first.

For both the css and clipboard problems, there are loads of well known and
supported libraries if supporting IE is in scope of your project.

~~~
nailer
Babel's been great, but currently most browsers don't need it - the only one
that does is the topic of this thread.

Flex and grid are hard to emulate. So is clipboard.

------
raju
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] - [http://looselytyped.com/blog/2012/08/22/on-prototypal-
inheri...](http://looselytyped.com/blog/2012/08/22/on-prototypal-inheritance-
part-ii/)

------
hannofcart
There are two things I have always wondered:

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?

~~~
nerdponx
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.

~~~
naasking
> What are typeclasses if not inheritance?

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.

------
sAbakumoff
Shameless plug - here is my description of how inheritance works in JS.
[https://github.com/sAbakumoff/Pritle/blob/master/2.Inhertian...](https://github.com/sAbakumoff/Pritle/blob/master/2.Inhertiance.md)

------
mici
Great article! A few things have caught my eye:

> MyApp.users = MyApp.user || {};

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.

~~~
elnygren

      foo = foo || {}
    

"mark foo as being foo if it is already defined or as an empty new object {}
if it is not"

It's just to not accidentally set a already defined foo as an empty object
incase foo is already defined. Yeah... JavaScript...

Another common idiom:

    
    
      const PORT = process.env.PORT || 8080
    

The || (logical OR) can be used for setting a default incase the value before
it is falsey (null, undefined, false...).

~~~
rco8786
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.

~~~
chriswarbo
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.

~~~
marcosdumay
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.

~~~
chriswarbo
> It will work for `foo = None`

Yes, but in that case the variable is irrelevant:

    
    
        foo = None
        foo or "default"
    

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
        >>>

------
EdSharkey
Here's a fun tool for visualizing prototype chains in random code.

[http://www.objectplayground.com](http://www.objectplayground.com)

------
codeulike
It all looks very tidy when you see it set out like that.

~~~
BigJono
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.

~~~
kowdermeister
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.

~~~
mileycyrusXOXO
That is because Java and C# use classical OO. Javascript does not, it uses
prototypal OO.

Classes are static contracts that define the state and behavior of object
instances.

Javascript objects are not contractually obligated to have the state and
behavior of a 'class'.

~~~
kowdermeister
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)](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.

------
snek
I feel like this article is 30 steps backward instead of a few steps forward.

------
leyth
Plagiarized, isn’t it?

