
JS Objects: Inherited a Mess - youngtaff
http://davidwalsh.name/javascript-objects
======
lispm
It's prototypical OO. Don't swim against the current. Swim with the current.

It's not inheritance - it is delegation.

It's just like in several other object-oriented languages: Self, NewtonScript
( <http://waltersmith.us/newton/OOPSLA95.pdf> ), Object Lisp (
<http://lispm.dyndns.org/docs/ObjectLisp-Manual.pdf> ), MacFrames, ...

This is a classic example that it is difficult to unlearn a concept.

Q: how long does it take to learn prototype-based OO?

A: a day is sufficient. If you know class-based OO you'll need three days.

~~~
PommeDeTerre
Prototype-based OO is one of those concepts that sounds good, but it's just
not what's actually needed in practice. Class-based OO just happens to be more
effective and useful when dealing with real-world problems.

I don't think it's a problem with developers not understanding prototype-based
OO; they do. It's just that they run into situations time and time again where
class-based OO is a better option. Yet since JavaScript doesn't (yet) offer
proper class-based OO functionality, developers needing or desiring such
functionality are forced to implement it themselves.

As anyone who has worked on any sizable, multi-developer JavaScript code base
will surely know, there are many different approaches to simulating proper
class-based OO in JavaScript. The maintenance headaches this causes are very
real.

The direction of the JavaScript current is just flat out wrong. It's not that
developers should stop swimming against it; they're going in the right
direction. The current itself should be reversed so that it aides the
developers in the direction they want to go, rather than continually ramming
against them.

~~~
nadaviv
> It's just that they run into situations time and time again where class-
> based OO is a better option

Can you give an example of such situation? My experience with prototype-based
inheritance is quite different - I find that it can do everything that class-
based inheritance can do, and more.

~~~
tracker1
What's funny, is I tend to deal directly with raw JS objects as models, then
use them against modules/functions. Rarely do I ever do inheritance, or
reference this.* except when dealing with monad-like utilities such as jQuery
or MomentJS.

My life is much happier this way, it's effective and it works... Yes, it's
much closer to a C-like way of dealing with libraries, but without all the
messy issues like pointer logic or memory management.

People need to stop trying to shove JS's triangle into a OO's round hole.

------
ender7
"Inheritance" doesn't really exist in JS. We use that word because we don't
have a better substitute, but what Javascript has is simply _code sharing_.
You can share code between multiple objects. This is accomplished by using
prototypes. An object has access to all the code defined on its prototype (and
its prototype's prototype, and...). If two objects have the same prototype
they will have access to the same methods.

Now, unfortunately, the native Javascript way of saying "please set the
prototype of this object to X" is not very intuitive. So again we reused an
existing word -- "class" -- and defined it to be "a thing that creates an
object and sets its prototype to be what I want".

However, actually creating these class things is painful and verbose in
vanilla Javascript, so everyone uses a library to do it for them. I use
classdef [1] because I wrote it and it works just the way I want it to, but
seriously there are a million options out there. Go find one and use it.

[1] <https://github.com/7sempra/classdef>

~~~
tantalor
I was taught that the practical purpose of inheritance is to share code.
Nowadays we call that idea "DRY". Classical inheritance is a means to satisfy
DRY.

In JavaScript, the same concept exists, and it's sometimes called "prototypal
inheritance" (since there are no classes).

<http://javascript.crockford.com/prototypal.html>

~~~
jefffoster
I've always thought inheritance is used to model is-a relationships. Sharing
code may be a side effect, but it's certainly not the reason to use it.

Using inheritance to share code is usually better achieved by factoring that
code out to a separate object and having the objects in a inheritance
relationship use it by composition.

~~~
justincormack
Hmm, interesting view. But why would you want to model is-a relationships?
Other than to share code?

~~~
AndrewDucker
Think of it as enforced documentation.

If I say that my object is a Customer then I know what can be done with it. If
I have a method that says it takes a Customer object then the calling point
knows what to pass in, and my method knows it can rely on that object
satisfying certain conditions.

Basically it removes (some of) the need to document separately, and it
enforces that the documentation is adhered to.

------
wsc981
Nice article. Never written much JavaScript myself, but as an Objective-C /
iOS developer I understand the delegation part well, as it's an integral part
of Apple's UIKit and AppKit API's. Though the concept was kind of alien to me
before I started writing Objective-C code.

A few years ago, when I started learning Objective-C I used a book written by
Aaron Hillegass. I liked the way he explained delegation vs. subclassing:

> Once upon a time (before Baywatch) there was a man with no name. Knight
> Industries decided that if this man were given guns and wheels and booster
> rockets, he would be the perfect crime-fighting tool. First they thought,
> "Let's subclass him and override everything we need to add the guns and
> wheels and booster rockets." The problem was to subclass Michael Knight, you
> would need to know an awful lot about his guts so that you could wire them
> to guns and booster rockets. So instead they created a helper object
> (delegate), the Knight Industries 2000 Super Car, or "Kitt."

> Notice how this is different from the RoboCop approach. RoboCop was a man
> subclassed and extended. The whole RoboCop project involved dozens of
> surgeons to extend the man's brain into a fighting machine. This is the
> approach taken by many object-oriented frameworks.

Source: Cocoa Programming for Mac OS X by Aaron Hillegass.

------
mcmire
The real mess is how in ES6 they (the ES6 WG I mean) are furthering the
illusion that JS supports classical OO, which is completely crazy. They should
be going the other direction (and I think /be wanted to) but they steered away
from that and seem to think that mixing syntaxes and thus concepts is the
right move. I would imagine this article series will talk that eventually,
though, kind of hard not to.

~~~
jarek-foksa
JavaScript was a pseudo-classical language from the beginning. JS constructors
were and still are the core language feature that clearly tries to mimic
classes from Java. I agree that's it's awful, but it can't be depracated or
removed from the language because there is so much code relying on it.

Evolving JS into language with minimal dynamic classes such as Python or Ruby
should be easy as all interfaces are already "classical", you just need to add
some syntactic sugar. This approach was already proved to work by CoffeeScript
and TypeScript. I can't imagine how JS could be evolved into clean prototypal
language such Io without breaking backwards compatibility.

There is no hope for JavaScript to become elegant prototypal language because
of the design mistakes that were done in the past. All that TC39 /
ECMAScript.next committee can do is put even more lipstick on a pig.

[http://this-plt-life.tumblr.com/post/36425234595/when-somebo...](http://this-
plt-life.tumblr.com/post/36425234595/when-somebody-tries-to-explain-
javascripts-prototype)

[http://this-plt-life.tumblr.com/post/41438931672/when-somebo...](http://this-
plt-life.tumblr.com/post/41438931672/when-somebody-says-js-has-a-beautiful-
object-model)

~~~
_getify
Actually, the evolution of the language has been adding "class-like" features
over time. It was most definitely not designed originally to mimic classes.
That's been the demand of all the classicists coming to the language. There
are those of us who wish for the language to not have all those things.

In parts 2 and 3, I'll make the case for why I think all those things don't
belong in JS and should be removed or avoided.

~~~
jarek-foksa
There was really little evolution of the language since 1995. It was initially
launched as a "perfect complement to Java" [1] and until recently its
development was stalled.

Constructors and "new" were there from the beginning. Nobody have even noticed
the prototypal nature of JS until people like Crockford started evangelising
it 10 years later, which in turn resulted in the addition of Object.create()
in ES5.

[1] <http://www2.ldc.lu.se/temadag95/javascript.txt>

~~~
_getify
I'm not sure the actual history bears out your assertion that 1995 was the
fix-point date for all/most of these concepts.

AIUI, functions were not originally first-class citizens. My understanding is
(and I may very well be incorrect), in these very early days, functions not
being objects precluded an awful lot of what we currently "know" to be true
about how JS emulates "classes" with function.prototype. I tried to find good
citations for this fact, but I'm having trouble finding good "early
JavaScript" history.

I do know that at least as early as ES1, in mid-1997, we had constructors with
prototypes and "new". [1]

In any case, besides `Object.create()` which you've noted, here are some other
milestones in the evolution of "OO in JS" I could find:

`instanceof` was added in JavaScript 1.4 [2], which was sometime after Oct
1998 [3], probably officially in ES3.

`Object#isPrototypeOf()` was added in ES3 [4], which was around late 1999.

`Object.getPrototypeOf()` was added in ES5 [5], which was around 2009.

[1] [http://www.ecma-international.org/publications/files/ECMA-
ST...](http://www.ecma-international.org/publications/files/ECMA-ST-
ARCH/ECMA-262,%201st%20edition,%20June%201997.pdf)

[2] [https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Operators/instanceof)

[3] <http://en.wikipedia.org/wiki/Javascript#Version_history>

[4] [https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Global_Objects/Object/isPrototypeOf)

[5] [https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Global_Objects/Object/getPrototypeOf)

------
38leinad
I never find an answer to my most daunting question: how is the pattern for
doing something like a super call in this prototypal model?
bar.prototype.methodname? what if the method is only defined in the proto-
prototype? I.e. Foo? Do I then have to explictly know this and write
bar.prototype.prototype.methodname?

I hope you know what I mean. This concept of super-calls does not transfer
well to prototypal inheritance for me. Are there other patterns that should be
used instead?

~~~
_getify
In part 2, which should be published later today, I am going to address
"polymorphism" directly, and the punchline is that I'm going to argue that JS
doesn't have a good "OO" way of doing relative super calls, and thus you
should try to avoid polymorphism. The workaround is indeed an implicit mixin,
where you do "ParentConstructor.prototype.method.call(this)", but even though
that "works", it's brittle to be hard-wiring your "inheritance" chain across
all your polymorphic overridden methods.

~~~
38leinad
thanks for the clarification. that helped a lot to get the understanding
straight. always thought I am missing something fundamentally. Looking forward
to the read.

in the end i also think super-calls are not a very good concept as you
normally don't know what the super calls are doing internally, but somehow it
seems like the way to go as almost every mainstream language/framework is
supporting/doing it... but i guess that's the general bitter taste i get from
classical inheritance...

------
_getify
To expound on the metaphor I put in this article about inheritance and my
mother-in-law:

> If you try to illustrate behavior delegation in terms of the "blueprint"
> metaphor, you quickly see how it totally breaks down. There's no way that my
> home, lacking a guest bedroom, could simply refer to another house, or to
> the original blueprints, to provide a bedroom for my mother-in-law when she
> comes to visit.

OTOH, I can delegate my mother-in-law to go stay in a hotel room. Or, I can
delegate my mother-in-law to stay on a neighbor's couch, but I can send along
sheets and pillows for her to use.

In either case, I'm not mutating my own home (inheritance) to handle her
visit, I'm relying on someone else to handle it. But it's still _my_ mother-
in-law who I send elsewhere, and in fact, I can make sure she takes some
"context" (aka, pillows) with her when she does.

Again, metaphors are never perfect, but I just thought I'd complete the
perspective to contrast inheritance vs. behavior delegation.

------
pjmlp
This problem is caused by developers only familiar with OO as it is presented
by Object Pascal/C++/Java/C# and so on.

There are however many other ways to do OO and JavaScript just happens to use
another way. The language is not alone, Self, BETA, C@, Dylan, CLOS also have
different ways from mainstream OO.

------
eaurouge
His "behavior delegation" chain looks a lot like the method lookup chain [1]
in Ruby, a pure object-oriented language.

1\. [http://madebydna.com/all/code/2011/06/24/eigenclasses-
demyst...](http://madebydna.com/all/code/2011/06/24/eigenclasses-
demystified.html)

~~~
mattdawson
The same is true in Python - in single inheritance cases. (The rules for
Python's method resolution order are more complex where multiple inheritance
are involved[1].)

1\. [http://python-history.blogspot.com/2010/06/method-
resolution...](http://python-history.blogspot.com/2010/06/method-resolution-
order.html)

------
estavaro
My confession on the matter: Working with OO in JS made me a "cargo cultist."
I wasn't entirely aware of how it worked, but just glad that it did for as
long as I had used it. The last JS library I used was PrototypeJS which had
some custom support for classes.

I learned about non-OO JS code in the YUI framework. I didn't like what I saw
as it precluded a lot of "private and hidden" code.

I've deposited a lot of goodwill on the Dart language that compiles to JS. My
reward is that Dart has library and class support that "just works! (TM)" Then
again, I abhor the using of types that Dart allows as I think people waste a
lot of time giving types to APIs and obscure the intention of the code,
ultimately making the platform less popular.

~~~
ahoge
>I think people waste a lot of time giving types to APIs and obscure the
intention of the code

What do you mean? Adding types to the surface area (arguments and return
types) removes a lot of friction.

I'm using jQuery for a couple of years. I still have to look at its docs
almost every day I use it. Today, I had to check if the "selector" argument of
"children()" is optional (spoiler: it is).

Also, having the type annotations there makes the intention so much clearer.
The name and the type of the argument is usually all you need to figure out
what it does.

I _really_ like that about Dart.

~~~
estavaro
The problem is that it makes people more concerned about getting the types
right than about giving people shortcuts.

The API designers end up creating a multitude of APIs to deal with different
type parameters and so on, to get their "generics" right and so on.

It makes the APIs look like Java APIs more than they jQuery ones.

Part of the problem is that the designers really want to get the types of
classes and so on right on their parameters and return types. The types go
beyond the primitives.

I've been able to watch it unfold and it's rather painful. The result looks
less like a scripting language API and more like a C# collection of libraries,
for better or for worse.

~~~
ahoge
> giving people shortcuts

I don't see any problem there. The code is very compact. There are lambda
expressions, method cascades, and user defined operators.

Also, structure is baked in. You don't need any of that AMD boilerplate code.
Annotations are also baked in. You don't need to write those lengthy doc
comments.

Additionally, you can auto-complete everything.

> It makes the APIs look like Java APIs more than they jQuery ones.

With jQuery, you often have those "options" objects which force you to check
the documentation even if your editor is somewhat jQuery aware.

With Dart, you can just use named arguments. It's also clearer what the
default values are. Of course things are also a lot easier if the machine can
tell what you're trying to do.

> more like a C# collection of libraries

Well, that's the whole point. If you put type annotations at the API
boundaries, those annotations can be used for documentation (fully cross-
referenced), call-tips, auto-completion, type inference, and basic sanity
checks.

This gets rid of lots of friction. Even if your own code doesn't include any
types, the editor will be able to tell what's going on in many cases.

E.g. it knows that `1 / 3` results in a `double`, which has a
`toStringAsFixed` method, which returns a `String`, which has a `length`
getter, which returns an `int`.

So, if you accidentally write "lenght", the editor will tell you about your
mistake right away. Well, you won't even make that typo in first place,
because you'll just auto-complete that word.

Furthermore, if you store the value of `length` in a `var`, the editor will
remember that it's actually an `int` and it will then notify you whenever
you're doing something weird with it.

All of that works just because the libraries you're using are annotated.

~~~
estavaro
The help of an IDE restricts the use of the language. It's the same for the
TypeScript variant. If you say "you need a Visual Studio" or the like to use
it comfortably, you're restricting the use-cases of the language.

I forgot to give the example of using "Enum-like" types instead of boolean
parameters, because boolean parameters don't give enough information, so then
you might need to pass something like MyClass.MYVALUE to a parameter rather
than true or false.

So yes, there's much to like and dislike. Needless to say, there are those
that need more type features from the language and toolset than it already
offers, even if it's kind of hard because to come up with more if some of it
needs to go into compiling down to JavaScript.

With more type features they would expect to have more features like real
Enums or what-have-you.

Even "var" declaration starts to look awkward in a language where types are
available. So things like "for (int i = 0; i < 10; i++) {}" are more natural
than "for (var i = 0; i < 10; i++)". And that's only the tip of the iceberg.

When you start declaring things like "listenToMouseEvent(MouseEvent e, () {})"
when using some event API, that's when it gets uglier still.

But yes, to each his own. JavaScript is still the leader in many ways,
including some basic performance despite not the extra type declarations. They
have really extracted nearly all of the performance allowed from JavaScript it
seems. So performance alone is not what will differentiate these other
languages from JavaScript.

------
yuchi
We're probably going to see some declination of the parasitic inheritance in
the next parts, none-the-less this article has been a good read. You don't
find a lot of _real_ JS article these days.

~~~
_getify
I will not be directly addressing "parasitic inheritance" as I never saw it to
be a terribly useful pattern, honestly. I see it very rarely used and even
more rarely referenced by that name.

The point I'd make about it here, though, which is generically reflected in
today's part 2 article, is that it's a fine pattern in and of itself, but the
reason I think it's a "distraction" is that it actually moves away from the
[[Prototype]] chain entirely.

You can use it as a bespoke pattern for combining two objects, but it's a
mistake/confusion to think this has anything to do with JS's underlying
delegation mechanism. The same point is made about mixins, and polymorphism
(which also requires implicit mixins).

~~~
yuchi
I have to admin part 2 perfectly sums my ideas about JS and classical OOP
inheritance. Looking forward part3 and its "solution".

------
chrishenn
When I was learning more about this, I found this[1] article to be of great
help.

I think the key idea is that JS is a prototype-based OO model. It's easy to
forget because there are so many abstractions[2] that act like a JS is a
static class based OO language.

[1] [http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-
genera...](http://dmitrysoshnikov.com/ecmascript/chapter-7-1-oop-general-
theory/) [2] <http://coffeescript.org/#classes>

------
argonaut
Does anyone know of a tutorial that breaks down (with code examples) all the
different methods of JS inheritance and their disadvantages/advantages? I
understand that Object.create is the now-recommended way to do things, but I
still get confused because there are a bajillion ways of modeling inheritance
in JS.

~~~
tantalor
Some patterns off the top of my head,

    
    
      1. Prototype
      2. Delegate
      3. Mixin
      4. Module
    

Understand how those patterns work and you should be able to understand how
the libraries vary.

Might also help: [http://stackoverflow.com/questions/1645027/popular-
javascrip...](http://stackoverflow.com/questions/1645027/popular-javascript-
inheritance-patterns)

------
DonPellegrino
I wrote this snippet of code to explain the concept of
function/hashmap/object/class to javascript beginners.
<http://jsfiddle.net/AXTdj/>

------
davidwalshblog
Part 2 has been published:

<http://davidwalsh.name/javascript-objects-distractions>

------
dreamdu5t
JS is prototypical OO. There isn't supposed to be class inheritance. And no,
Kyle Simpson is not a "legend." I've never even heard of him. Step outside
your Twitter stream for a moment please.

