Treehouse

JS Objects: De”construct”ion

By on  

JS Objects: TL;DR

JavaScript has been plagued since the beginning with misunderstanding and awkwardness around its "prototypal inheritance" system, mostly due to the fact that "inheritance" isn't how JS works at all, and trying to do that only leads to gotchas and confusions that we have to pave over with user-land helper libs. Instead, embracing that JS has "behavior delegation" (merely delegation links between objects) fits naturally with how JS syntax works, which creates more sensible code without the need of helpers.

When you set aside distractions like mixins, polymorphism, composition, classes, constructors, and instances, and only focus on the objects that link to each other, you gain a powerful tool in behavior delegation that is easier to write, reason about, explain, and code-maintain. Simpler is better. JS is "objects-only" (OO). Leave the classes to those other languages!

Due Thanks

I'd like to thank the following amazing devs for their generous time in feedback/tech review of this article series: David Bruant, Hugh Wood, Mark Trostler, and Mark McDonnell. I am also honored that David Walsh wanted to publish these articles on his fantastic blog.

Complete Series

In part 1 of this article series (which you should totally go read if you haven't yet!), I revisited an idea not original to me: JS doesn't have "inheritance" in the traditional sense, and what it does have is more appropriately labeled "behavior delegation" -- the ability of one object to delegate a method or property access which it cannot handle over to another object which can handle it.

Then, in part 2, I addressed several distractions which I think obfuscate JS's true object-oriented identity, including "custom types", "mixins", "polymorphism" (which we'll come back to again later), and even the new "class syntax" coming in ES6. I suggested that to understand (and leverage) better the [[Prototype]], we needed to strip away the cruft. Here, I will attempt to do that.

Turtles Objects all the way down up

The key realization, the punchline to this entire article series, is that [[Prototype]] is really only about linking one object to another object, for the purposes of delegating, if the first object cannot handle a property or method access but the second can. In other words, it's only objects, linked to other objects. That's really all JS has.

In a sense, JS is the purest essence of a "object-oriented (OO)" language, in that it really is all about objects. In contrast to most other languages, JS is somewhat unique that you can actually create objects directly without the notion of classes or other abstractions. That's a powerful and brilliant feature!

People often bash JavaScript, but it’s one of the few prog languages that let you directly create objects. Others: Lua, Dylan, Cecil.

— Axel Rauschmayer (@rauschma) April 9, 2013

JavaScript legitimately is "object-oriented", and perhaps we shouldn't have used that term for the other languages which imply a lot more than just "objects". Maybe "class-oriented" would have been more accurate, which would have freed us up to use "object-oriented" for JS. Of course, as I argued in part 1, what everybody means when they use some term, matters, so it's far too late to redefine or bend the commonly accepted "object-oriented" to my own purposes, much as I'd like to.

I'm mildly tempted, however, to just hijack the abbreviation of "OO" to mean "objects-only" instead of "object-oriented", but I bet that probably wouldn't get anywhere, either. So, for our purposes here, let's just sayJavaScript is "object-based (OB)" to clarify against "object-oriented (OO)".

Whatever we call it, we normally tap into this object mechanism by following the "OO way": we create a function which we use as a "constructor", and we call that function with new so that we can "instantiate" our "class", which we specify with the constructor function together with its subsequent .prototype additions... but all that is like a magician's sleight of hand that dazzles you over here to distract you from what's really going on over there.

What really matters, at the end of the trick, is that two objects end up linked to each other via the[[Prototype]] chain.

Codez Plz

Before we can derive and understand that simpler view of "objects-only" or "object-based", we need to understand what actually gets created and linked when we build up some "inherited" objects in JavaScript. Not only are we going to see what happens by default, but what doesn't happen.

Take this code for our main example:

function Foo(who) {
    this.me = who;
}

Foo.prototype.identify = function() {
    return "I am " + this.me;
};

function Bar(who) {
    Foo.call(this,who);
}

Bar.prototype = Object.create(Foo.prototype);
// NOTE: .constructor is borked here, need to fix

Bar.prototype.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = new Bar("b1");
var b2 = new Bar("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

Note: Some people write Bar.prototype = Object.create(Foo.prototype); as Bar.prototype = new Foo();. Both approaches end up with the same linked objects, where Bar.prototype is an object linked via its[[Prototype]] to Foo.prototype. The only real difference is whether or not the Foo function is called during the creation of Bar.prototype. Depending on your circumstances and intent, you may or may not want that to happen, so let's consider them roughly interchangable but with different purposes.

What we have is an object labeled Foo.prototype with an identify() method, and another object calledBar.prototype with a speak() method. Bar.prototype is a new empty object that is [[Prototype]]-linked to Foo.prototype. Then we have two objects b1 and b2, who each are each respectively linked via their own [[Prototype]] to Bar.prototypeb1 and b2 also have an "owned property" directly on each of them called me, which respectively holds the values "b1" and "b2".

Let's take a visual look at the relationships implied by the above code snippet:

Note: All the [[Prototype]] links in the diagram also mention a ".__proto__" property__proto__ is a formerly non-standard property (which exists in most but not all JS environments) to expose the internal [[Prototype]]chain. As of ES6, however, it will be standardized.

I left a whole bunch of detail out of that diagram, intentionally, so it was even remotely digestable. But of course, since JS is all objects, all the linkages and ancestry of each item can be fully traced. We'll come back to all the omitted parts of this diagram in a little bit.

Note in this diagram that the function constructors all have a .prototype property pointing at an object. As we've been suggesting, the object is what we really care about, and in this way of viewing the JS object mechanism, the way we get that object is to look at a constructor function's .prototype. The function doesn't really serve any particularly important role.

I know a whole bunch of you just screamed out, "sure it does! it runs constructor code to initialize the new object!" OK, you're technically right. Foo() has some code in it which is ultimately run against b1 and b2.

But the devil's always in the details. First, we don't need a constructor function to run such code. That's just one way of getting that outcome. And I'm going to suggest it's a more distracting approach.

Secondly, unlike C++, the base-class/superclass Foo() "constructor" doesn't automatically get called when you run the child-class Bar() "constructor" to make b1 and b2. So, like Java, we have to manually call theFoo() function from Bar(), but unlike Java, we have to do so with a variation of the explicit "mixin" pattern (I'd probably call it "implicit mixin" here) to make it work like we expect. That's an ugly detail that is very easy to forget or get wrong.

So, where you'd probably argue with me that "constructor" functions are useful being automatically called at the construction of an object, I'd point out that this is true for only the immediate level, not for the entire "chain of inheritance", which means that automatic behavior is pretty limited/shallow in utility.

Polymorphism redux

Moreover, we see here the first hint of the problems with relative polymorphism in JS: you can't do it! I can't tellBar() to automatically and relatively call his ancestor constructor(s), via a relative reference. I have to manually call (aka, "borrow") the Foo() function (it's not a constructor here, just a normal function call!) from inside ofBar(), and to make sure the this is bound correctly, I have to do the slightly more awkward .call(this)style of code. Ugh.

What may not be obvious until you go back and look closer at the diagram above is that the Foo() function isnot related in any useful/practical way to the Bar() function. The Foo() function does not even appear in the "inheritance" (aka "delegation") chain of Bar.prototype object. The fact that there are some lines you can follow on the graph for indirect relationships doesn't mean that those relationships are what you'd want to rely on in your code.

The problem with polymorphism we're seeing here is not only for "constructor" functions. Any function at one level of the [[Prototype]] chain that wants to call up to an ancestor with the same name must do so via this manual implicit mixin approach just like we did inside of Bar() above. We have no effective way of making relative references up the chain.

Importantly, this means that not only do we establish the link between Bar and Foo once at "class" definition, but every single polymorphic reference also has to be hardcoded with the direct relationship. This significantly decreases the flexibility and maintainability of your code. As soon as you make a function hard-coded with implicit mixin to an "ancestor", now your function can't be "borrowed" as easily by other objects without those possible unintended side effects.

OK, so let's say you agree with me at this point that polymoprhism in JS is more trouble than it's worth. Using constructor-based coding to wire JS objects to each other forces you into the problems of polymorphism.

.constructor

Another detail that's easy to miss is that an object's .constructor property really doesn't behave like we'd probably expect. It's correct at the Foo() level of the graph, but below that, at Bar() and b1 / b2, notice that the implied linkage there shows .constructor references, strangely, still pointing at Foo.

Actually, what this means is that the only time a .constructor property is added to an object is when that object is the default .prototype attached to a declared function, as is the case of Foo(). When objects are created via new Fn() or Object.create(..) calls, those objects don't get a .constructor added to them.

Let me say that again: an object created by a constructor doesn't actually get a .constructor property to point to which constructor it was created by. This is an extremely common misconception.

So if you reference b1.constructor for instance, then you're actually going to delegate up the chain a few links, to Foo.prototype. Of course, Foo.prototype has a .constructor property and it's pointing at Foo like you'd expect.

What's that mean? In the above snippet, right after you perform Bar.prototype = Object.create(Foo) (or even if you'd done Bar.prototype = new Foo()), if you plan to rely on the .constructor property (which many do), you need to perform an extra step, right where I put the JS "Note:" comment:

//...
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar; // <-- add this line!
//...

Then b1.constructor references will delegate to that Bar.prototype level, and will "correctly" point at Bar()as you'd probably have expected. Ugh...**more syntax gotchas** that user-land libs always have to "fix" for us.

Furthermore, the fact that Foo.prototype has a .constructor property pointing at Foo is strange, when you think about "constructor" the way most people do. It's nice that it gives objects created by new Foo() a way to delegate to a .constructor property access and find Foo(), but it's bizarre where .constructor actually lives.

It implies that Foo() constructed Foo.prototype, but that's nonsense. Foo() had nothing to do with creating the default Foo.prototypeFoo.prototype defaults to an empty object that was actually constructed by the built-in Object() constructor.

So we have to change how we think of what the .constructor property means. It does not mean "the constructor this object was created by". It actually means "the constructor which creates any objects that end up getting [[Prototype]] linked to this object." Subtle but super important difference to get straight.

Point? These confusions only happen/matter if you're using constructor-style code, so it's the choice of this style of code that opts you into the problems. You don't have to live with that pain. There's a better, simpler way!

The Whole Pie

Now let's look at everything that's actually implied by the above snippet of code. Ready for the whole messy thing?

Take a few minutes to just take all that in. Why show you such a complex diagram?

This diagram actually shows you where some of JavaScript's functionality comes from, where before you might have just never considered how it all worked. For instance, have you wondered how all functions are able to use behavior such as call()apply()bind(), etc? You may have assumed each function has that behavior built-in, but as you can see from this diagram, functions delegate up their [[Prototype]] chain to handle those behaviors.

While the behavior delegation part is sensible and useful, consider all the implied complexity of constructor-style coding as visualized here. It's pretty tough to trace all the different entities and diagrams and make much sense of it all. A lot of that complexity comes from the function constructors. (here's the same complete graph but with the implied relationship lines omitted, if that helps to digest)

If you take that diagram, and remove all the functions and any associated arrows (which we'll see in just a moment), you're left with "objects-only", and you'll have a much more simplified view of the JS objects world.

Simpler: Object -> Object

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. --Antoine de Saint-Exupery

For refresher, the same prototype-style code from above:

function Foo(who) {
    this.me = who;
}

Foo.prototype.identify = function() {
    return "I am " + this.me;
};

function Bar(who) {
    Foo.call(this,who);
}

Bar.prototype = Object.create(Foo.prototype);
// NOTE: .constructor is borked here, need to fix

Bar.prototype.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = new Bar("b1");
var b2 = new Bar("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

Now, let's instead consider this alternative snippet of code, which accomplishes exactly the same, but it does so without any of the confusion/distraction of "constructor functions", new.prototype, etc. It just creates several objects and links them together.

var Foo = {
    init: function(who) {
        this.me = who;
    },
    identify: function() {
        return "I am " + this.me;
    }
};

var Bar = Object.create(Foo);

Bar.speak = function() {
    alert("Hello, " + this.identify() + ".");
};

var b1 = Object.create(Bar);
b1.init("b1");
var b2 = Object.create(Bar);
b2.init("b2");

b1.speak(); // alerts: "Hello, I am b1."
b2.speak(); // alerts: "Hello, I am b2."

Let's try to take some comparison looks between this snippet and the previous one. They both accomplish the same thing, but there's some important differences in how we get there.

First of all, Bar and Foo are now just objects, they're not functions or constructors anymore. I left them as capital letters just for the symmetry and because some people feel better with them. They make it clear that the objects being linked are what we cared about all along, so instead of the indirectness of linking Bar.prototype toFoo.prototype, we just make Foo and Bar objects themselves and link themAND, we only need one line of code to link them, instead of the extra ugly polymorphic linkage. Bam!

Instead of calling function constructors like new Bar(..), we use Object.create(..), which is an ES5 helper that allows us to create a new object and optionally provide another object to [[Prototype]] link it to. We get the same outcome (object creation and linkage) as a constructor call, but without needing the constructor. BTW, there's a simple non-ES5 polyfill for Object.create(..), so you can safely use this style of code in all browsers without concern.

Secondly, notice that because we're not worried about constructors anymore, we have eliminated any concerns about awkward polymorphisms forcing us to do manual implied mixins to call Foo() from Bar(). Instead, we put the code we wanted to run to initialize our objects into a init() method, on Foo, and we can now callb1.init(..) directly via the delegation chain and it "magically" just works like we want.

So, we have a tradeoff here. We don't get automatic constructor calls, which means we create the object likevar b1 = Object.create(Bar) and then we have to additionally call b1.init("b1"). That's "more code".

But the benefits we get, which I think are much better and well worth it, are no awkwardness with the linkage between Foo and Bar -- instead we leverage [[Prototype]] delegation to get at the code reuse ininit(). Also, no more verbose/repetitive .prototype references, and neither do we need to use.call(this) nearly as often (especially if we avoid polymorphism!).

Looks are everything

And to visualize the simplicity this approach brings us, here's the diagram when we remove the functions entirely and focus only on the objects:

I don't know about you, but I just think that mental model is so much cleaner, and the bonus is that its semantics perfectly match the code.

I have shown you simple enough code using only core JS syntax, that I don't need any helper libraries to wire up my objects. Of course, I could use one, but why? Simpler is better. KISS.

Any fool can make something complicated. It takes a genius to make it simple. --Woody Guthrie

For the record, I'm not even remotely the genius here. Brendan Eich, creator of our language, was the genius for making something so powerful yet so simple.

Object self-reflection

Last thing to address: how does this simplification affect the process of reflecting on an object? In other words, can we inspect an object and find out about its relationships to other objects?

For prototype-style code, reflection looks like this:

b1 instanceof Bar; // true
b2 instanceof Bar; // true
b1 instanceof Foo; // true
b2 instanceof Foo; // true
Bar.prototype instanceof Foo; // true
Object.getPrototypeOf(b1) === Bar.prototype; // true
Object.getPrototypeOf(b2) === Bar.prototype; // true
Object.getPrototypeOf(Bar.prototype) === Foo.prototype; // true

Notice that you're using instanceof and having to think in terms of the constructor functions that made your objects, and their .prototypes, rather than just reflecting on the objects themselves. Each of those reflections comes with slightly more mental tax as a result.

And when there's only objects?

Bar.isPrototypeOf(b1); // true
Bar.isPrototypeOf(b2); // true
Foo.isPrototypeOf(b1); // true
Foo.isPrototypeOf(b2); // true
Foo.isPrototypeOf(Bar); // true
Object.getPrototypeOf(b1) === Bar; // true
Object.getPrototypeOf(b2) === Bar; // true
Object.getPrototypeOf(Bar) === Foo; // true

By contrast, reflection on objects is only about the objects. There's no awkward references to a constructor's.prototype property for the checks. You can just inspect if one object is related via [[Prototype]] to another object. Same capabilities as above, but with less mental tax.

Moreover, as I mentioned in part 2, this sort of explicit object reflection is preferable and more robust/reliable than implicit detection through duck typing.

Object.wrapItUpAlready()

Take a deep breath! That was a lot to take in. If you've followed all 3 parts of the article series, I hope by now you see the bottom line: JS has objects and when we link them, we get powerful behavior delegation.

There's just no need to pile on class-orientation on top of such a great system, because it ultimately just leads to the confusion and distraction that has kept JS' object mechanism shrouded and covered up by all these helper libraries and misunderstandings about JS syntax.

If you stop thinking about inheritance, and instead think with the arrows headed the other way: delegation, your JS code will be simpler. Remember: it's just objects linked to objects!

Kyle Simpson

About Kyle Simpson

Kyle Simpson is an Open Web Evangelist from Austin, TX, who's passionate about all things JavaScript. He's an author, workshop trainer, tech speaker, and OSS contributor/leader.

ydkjs-2.png

Recent Features

Incredible Demos

Discussion

  1. Niek

    Nice article! But most of the time I’m using the “init/constructor” function on the Bar object to run additional initialization code (in addition to the Foo initialization code), and that functionality is not available in the “Object -> Object” example. Code re-use through polymorphism is difficult in JavaScript without using any tricks or hard-linking the Foo and Bar objects. I hope ES6 will solve this.

    • Yes, very important point you’ve made.

      If you need multi-level initialization, you have the unfortunate choice that you either use the same name init() at each level, and then you deal with the frustrations of hard-coded polymorphic references, OR you can give each init task a unique name, which is often a better idea anyway, and if you do that, then this.fn() style calls will work safely (and relatively) through the [[Prototype]] delegation chain as you’d want.

      For instance, say you had one set of initialization at Foo level which set the identity, and another set of initialization at the Bar level which customized some output preferences:

      Foo.setupIdentity = function(who) { this.me = who; };
      //..
      Bar.setupOutputPrefs = function(prefs) { /* .. */ };
      Bar.init = function(who, prefs) {
         this.setupIdentity(who);
         this.setupOutputPrefs(prefs);
      };
      //..
      var bar1 = Object.create(Bar);
      bar1.init( "b1", { /*..*/ } );
      

      It’s better software practice to use specific task names rather than try to “overload” a generic name like “init”, so this sort of design is not only more maintainable, it happens to fit very well with the style of code I’ve presented here.

      Hopefully that helps! :)

    • Gregor Elke

      @Kyle you don’t have to hard-code the polymorphic reference:

      var foo = {init : function(){console.log('foo init'); this.foo = true}}
      var bar = Object.create(foo)
      bar.init= function(){
              Object.getPrototypeOf(Object.getPrototypeOf(this)).init.call(this)
              console.log('bar init')
              this.bar = true
      }
      var b = Object.create(bar)
      b.init() // foo init // bar init
      console.log(b.foo, b.bar) // true true
      

      it looks a bit ugly with the double calling getPrototypeOf, but it works, and is generic from this point. one gotcha is, that oyu have to check for the existence of the init method, at the end of the chain there is no such method anymore.

    • @Gregor-

      Unfortunately, that’s a very dangerous approach. It only works when you have 2 levels of the chain. If you ever had a third level, you’ll have to change all such occurrences with an extra getPrototypeOf call, and a fourth level later will mean yet another call in all those places. It’s a refactoring footgun of the worst variety.

    • I Should really check my code first:

      var super = function(obj, fnName) {
      	var current = Object.getPrototypeOf(obj);
      	while ((current = Object.getPrototypeOf(current))) {
      		if (typeof current[fnName] == 'function') {
      			return current[fnName].apply(obj, [].slice.call(arguments, 2));
      		}
      	}
      }
      
    • realised it wouldn’t work for the second super call, so here is one that should work based off of goog.base:

      var super = function(fn) {
      	var caller = super.caller;
      	var found;
      	for (var child = object.getPrototypeOf(this); child && child[fn] typeof == 'function'; child = Object.getPrototypeOf(child)) {
      		if (!found)
      			found = true;
      		else if (child[fn] != caller)
      			return child[fn].apply(this, [].slice.call(arguments, 1));
      	}
      }
      
    • @rhys I think your final code snippet makes my point for me. It is POSSIBLE to traverse the prototype chain each time you want to make a super call… that’s what my currentThis polyfill did. But it’s terribly ugly and inefficient, so much so that I’d argue it’s impractical to use such techniques. It’s exactly this kind of ugliness that I was referring to in several places when I condemned polymorphism (the relative kind) in JS.

      On a side note, you could have done:

      Bar.init = function() {
      Object.getPrototypeOf(Bar.prototype).init.call(this);
      };
      

      Technically, THAT is a relative sort of super call… where at least it isn’t hard coding Bar to Foo. However, there are gotchas with this approach too, and there is unquestionably a lot of ugliness to that sort of coding. That style of code is highly likely to be done wrongly, and even if it’s right, it’s harder to understand/maintain later. All of those are points I made throughout the article series on why that style of code is something I think that makes JS [[Prototype]] harder to use/understand. It’s not just a lack of syntactic sugar, it’s that fundamentally we don’t have a currentThis or super, and our workarounds for that are, IMO, uglier than polymorphism is worth.

      I posted another comment here on this article where I suggested another way to deal with multiple-levels of initialization without relying on polymorphism. That’s the style of code that I think is WAY better to write. Just my opinion, though.

  2. Thanks for the article. Could you recommend more material to study that approaches the language in the manner you do? My eventual project work will be for multi-player (local, 100 or fewer users) game and info-viz application with heavy use of MySQL data. Thanks again.

    • At the risk of sounding too glib, I have a blog I plan to write more on soon, and I’m also planning to launch a kickstarter in the next few days for a new book series I want to write on JS, so I think you should read more of my stuff! ;-) (keep an eye out here for announcements for my kickstarter)

      But, seriously, Angus Croll and I seem to have a lot of mindset about JS in common, and he writes some great stuff on his blog. Hope maybe that helps for now.

    • FYI, I have indeed launched my Kickstarter for the book series “You Don’t Know JS”. Check it out and help spread the word!

    • Oops, sorry, wrong link. Here’s the correct link.

  3. ariutta

    Thanks for this series. In the previous post, you said that composition “has plenty of goodness to it,” but you also call composition a “distraction.” When would you recommend using composition in a JavaScript project?

    • What I meant is that composition is one of many distractions that lead you into believing that behavior delegation is actually some bizarre sort of inheritance. When used on its own, composition is fine, but it shouldn’t be used in the context of creating “classes” as a workaround for the weirdnesses of JS’s system.

      As an example, you could have a Router object that you expose as a .router public property on your UIManager object, as opposed to wiring UIManager to delegate to Router via [[Prototype]]. This would be composition, as a property on an object that is itself some other object.

      What would sorta introduce confusion/distraction is if you used composition to hide the fact delegation wasn’t working the way you wanted classes to work.

      You can of course mix both patterns in the same project, but it’s HOW you use composition that matters, because it can be used for good or used as a tool of confusion by the inheritance crowd.

      The goal is to keep these concepts separate (and use them independently to their full power) instead of using one to confuse/conflate the other. Behavior delegation has been so confused and overlooked because of all the other OO jazz that I really wanted to set all that aside so we could examine BD all by itself.

      Does that clarify what I mean?

  4. ariutta

    Yes, that makes sense. Thanks again!

  5. Sebastian

    Great Post. I’m with you Constructor Functions only make things confusing.

    I always heard that Constructor Functions are a lot more performant than Object.create, so I made a test: http://jsperf.com/object-create-vs-constructor-function.

    At least in Chrome (V8) that seems to be the case. So this is a little gotcha of going the Object.prototype way.

    • I believe this has to do with the javascript engine. If you use a constructor function and don’t add or remove any of the instance properties after instantiation then the engine can cache the type of an object which speeds things up.

    • Yes, this is a difference between javascript engines. I’ve made a revision of your jsperf test using the two full code samples above at http://jsperf.com/object-create-vs-constructor-function/3. You can see that new is about 38% faster in Webkit, while Object.create is about 43% faster in Firefox. In Opera new is about a 4% faster. So you can see how the differences in the optimizations made by different js engines have a significant impact on the performance of the two styles.

  6. Sebastian

    I meant Object.create way.

  7. db

    Nice article. I think this is a really interesting approach to defining “class” structures in js. However, I’m going to challenge your claim that this method works ‘without any of the confusion/distraction of “constructor functions”, new, .prototype, etc.’ All of those aspects are still there, just hidden within Object.create(). The polyfill implementation from mozilla’s site gives a glimpse into what’s going on inside Object.create():

    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
    

    The technical aspect of creating constructor functions, setting up the prototype, and calling ‘new’ is still happening. This is evidenced by the fact that b1.constructor === Object. So at minimum the Object() function is getting called.

    The diagrams in this article depict purely conceptual differences. There’s no technical difference between using “new” or Object.create(). All the same constructor functions and prototype structures are getting created. It’s just happening behind the scenes with Object.create().

    That said, the coding approach you’ve outlined here is easy to understand and certainly clarifies delegation vs. inheritance concept. The only downside I see is that it breaks the use of ‘instanceof’, but I think that is acceptable given the option of using isPrototypeOf().

    On a side note, I’d recommend using a convention where the ‘init’ method returns ‘this’ to allow object creation to be chained:

    var Foo = {
        init: function(who) {
            this.me = who;
            return this;
        }
    };
    
    // ...
    
    var b1 = Object.create(Bar).init("b1"); // little cleaner
    

    Thanks for the article. It certainly got me thinking about things in a new way.

    • unfortunately isPrototypeOf only checks the prototype back one level, you may want to know if it’s got a certain prototype further back in the chain, though we can always fix that with something like:

      var hasPrototypeOf = function(proto) {
      	for (var current = this; current; current = Object.getPrototypeOf(current)) {
      		if (proto.isPrototypeOf(current)) {
      			return true;
      		}
      	}
      	return false;
      }
      
      var isType = hasPrototypeOf.call(myObject, typeToTestFor);
      
    • @rhys – I think you’re mistaken. isPrototypeOf() will check all the way up the chain, given the right context. So, in my coding example, Foo.isPrototypeOf(b1) is true, even though there’s two levels b1 -> Bar -> Foo.

    • @db – I think there’s a number of differences that make Object.create() different from constructor-style coding:

      1. the fact that all objects are created (or at least appear to be) by the Object() constructor doesn’t mean that constructors are happening throughout the rest of the code base. That’s basically a hidden implementation detail. AIUI, the JS engine is free to construct those objects however it wants, as long as the behavior stays the same, which is that the Object.prototype has a constructor that points to Object(). In short, I’m not entirely certain that those objects ARE actually created by Object(), but even if they are, that where the constructors stop in my example, as opposed to being strewn throughout.

      2. Again, implementation-wise, I don’t think the Object.create() actually needs to create an empty constructor function just to throw it away after creating our new object and linking it. Yes, that’s how the polyfill looks, but I don’t think necessarily that’s how it happens under the covers. Certainly, ONE BIG difference is that IF the constructor exists at all, it is hidden away and does not end up polluting the namespace.

      3. Another difference with Object.create() is that you can actually create an object that has absolutely no [[Prototype]], by calling Object.create(null), which is NOT something you can do with normal constructor-style coding.

      I stand by my claim: “without any of the confusion/distraction of ‘constructor functions’, new, .prototype, etc.” because none of those things are EVIDENT in the simplified code, which means that our code style is cleaner and easier to reason about, which was the whole point of the series. This isn’t a blog post about implementation details inside the JS engine, it’s about how we clean up our code style to reveal the true power of JS’s [[Prototype]] instead of shrouding it in the other confusions.

  8. Great posts … ANd thanks for all comments’ conttributors too

    Series was great for a newbie to OOP aspect of JS like me… I learnt a lot on OOP aspect of JS

  9. What about static members?

    Nice articles!

  10. Excellent post and series Kyle. I enjoyed comparing the outlined solution to what I do today. FWIW, I tend to go back and forth between “.constructor” and Object-based (i.e. Object.create).

    Definitely a trade-off and I still don’t see one being better than the other in “All” situations, unless the only goal is a simpler mental model. Object.create wins easily here.

    That being said, there is one thing I’ve been unable to work out with `Object.create` and `Object.getPrototypeOf` (to be fair, I haven’t been sufficiently motivated to solve this since I’ll happy lean on constructors to get the job done). Unless I am missing something simple, don’t we have a minor x-browser issue?

    The `Foo` object has no `.constructor` property and `__proto__` is not available everywhere. This makes it difficult to properly polyfill `Object.getPrototypeOf `.

    Have you been able to find a clean workaround?

    • Great question, Wil. I actually have looked into that, and was going to highlight it here but the article series was already pretty long and in-depth.

      I’ve played around with this notion of an Object.make(..) helper that does what Object.create(..) does, but also makes sure that every object it “makes” has, at minimum, a __proto__ and (delegated) access to isPrototypeOf().”>https://gist.github.com/getify/5226305″ rel=”nofollow”>an Object.make(..) helper that does what Object.create(..) does, but also makes sure that every object it “makes” has, at minimum, a __proto__ and (delegated) access to isPrototypeOf().

      an Object.make(..) helper that does what Object.create(..) does, but also makes sure that every object it “makes” has, at minimum, a __proto__ and (delegated) access to isPrototypeOf().”>

      This means that not only can old browsers still benefit from this approach, and use a simple polyfill for Object.getPrototypeOf() (which relies on __proto__), but even in new browsers, if you do Object.create(null), you end up getting a truly empty object that is NOT linked to Object.prototype, so it won’t have __proto__ or isPrototypeOf() either, which is a bummer. Object.make() normalizes that by adding back those, as bare minimum additions. Hope maybe that helps.

    • Doh. Sorry for the busted link. Here’s the correct link to Object.make().”>https://gist.github.com/getify/5226305″ rel=”nofollow”>correct link to Object.make().

      correct link to Object.make().”>
  11. I thoroughly enjoyed your 3-part article. What made it so much easier to understand was the visual representation that you gave, in addition to the well-explained subject with minimal code. I hope your upcoming books will be in a similar style.

    The only thing I have a hard time wrapping my head around is how to best handle this n that. Should I still use the that = this; pattern to access it within a function or is there a cleaner way I’m overlooking?

    • Jorge: there are 4 ways that this gets set inside a function execution.

      Was the function called with new? If so, the use the object new created.
      Was the function called with call or apply specifying an explicit this? If so, use it!
      Was the function called via a containing/owning object (context)? If so, use it!
      DEFAULT: global object

      When you learn those and all the different ways they play out (like using hard-binding with Function#bind(), etc) then you much more rarely need to mix `this` with closures, which is what the var self = this; kind of coding is all about. Every once in awhile you do it, but once you learn closures and `this` separately and deeply, the awkward mixes of them are reduced.

      BTW, one of the books in my You Don’t Know JS book series kickstarter is going to be all about this exact topic!

    • Awesome, thanks for the response. I thought you’d be nice enough to leave an answer.
      I’ve already chipped in for the books, just wanted to know about “this” straight-away so I can continue coding and researching on my own terms.
      Take your time with the books, make them good.
      I can’t wait :)

      PS: thanks for your answer too Wil

  12. Hi Jorge,

    Regarding `that = this`…You will likely get a different answer from just about anyone you ask; however, what I tend to come up with a name that makes sense given the context.

    Instead of:

    var that = this;

    If `this` is an audio player, I’ll do:

    var player = this;
  13. Webbower

    This is a great writeup. However, I’m running into some of the problems the other commenters have inquired about. I’m trying to figure out how to make this version of JS coding work for my purposes (as well as many other people’s, I’m sure), but it seems like there are things missing that classical OOP style handles more gracefully. This seems like a great idea in theory, but stumbles in a lot places for practical use. It would be awesome if you wrote a follow-up to all this that showed some practical implementations using this. There’s a lot of frameworks out there shimming class-based practices onto JS like the MV* and Widget libraries and many of them heavily utilize polymorphism to initialize up the chain and extend/override parent properties.

    I guess I’m putting out the challenge to put your money where your mouth is on this one. I’m definitely not one of the JS masters so my understanding is probably more limited than yours, but I’ve got a solid understanding of writing JS and I was trying to figure out how to build the foundations of a UI/Widget framework for my company using this method you excellently outlined, but I’m running into limitations (also taking into consideration my aforementioned skill level with JS).

    Thanks again for the great write-up!

    • I’d love to know more specifics on issues you’re having. But I agree we need to see real code, not just academic ideas. When/if I get something more concrete to show you, I will post back here. Also, watch my blog. :)

  14. How about Strictly-Objects as opposed to Object-Based? The latter has the same “fuzzy” feel to it as Object-Oriented does; neither really explains what it means.

    • I now use “OLOO” (objects-linked-to-other-object) to contrast with “OO”.

  15. Rotor

    Finally I can understand what all this .prototype stuff is all about! It makes so much more sense if you stick to patters for which the language was originally designed for.

  16. Andy

    This was a good writeup. Do you have any real life projects that are using the object only model? Or do you know of any popular libraries that are doing this?

  17. Yassine

    I finally understood ! I read dozens of articles and none was clearly saying things. Thank you so much!

  18. Dumitru "Mitică" UNGUREANU

    Hi.

    Looking at the Inspector in browser’s Web Developer Tools, things look virtually the same.

    With no subclass (no Bar), the init function for prototype replaces the constructor function for classical.

    With subclass (with Bar), we have an additional constructor function for every subclass, for “classical”.

    I know I can trust the Inspector. Your diagrams…?

    • That’s not correct. In the above final objects-only code snippets, init() exists **only** on Foo object, and will not be duplicated on Bar or on any of the b1, b2,… or even b997. Delegation will “share” that method across all those objects, which means there’s only one init() that they all use.

      Moreover, the objects-only style of code produces the exact same objects and the exact same [[Prototype]] relationships as function-constructor style code, but with vastly less code complexity.

  19. Alvaro

    Best javascript article ever!! I was looking exactly for this :) I’ve been reading dozens of blogs and books about how to write “good” object-oriented javascript code. But I was shocked by the creepy solutions proposed to do that. Thank you very much for enlighten us!!

  20. Michael Prescott

    I’m still trying to digest this. It seems it will lead to more succinct code for myself, and understandable. I’ve been inspecting objects and properties, and comparing to my current style’s results. It makes sense, but I’m lost on a few points. I really need to have multi-level initialization. In much of our work, we do:

    SubBase1.prototype.init = function() {
        Base1.prototype.init.call(this);
        // Additional SubBase1 initialization...
    };
    
    So, I'm trying to replicate that in some fashion using what I'm learning here.  Here's what I have:
    
    var Base2 = {
        prop1: 'prop1val',
    
        init: function() {
            console.log('Base2.init()');
            this.prop1 = this.prop1 + '-updated';
            this.prop2 = 'prop2val';
        }
    }
    
    var SubBase2 = Object.create(Base2);
    
    var sb2 = Object.create(SubBase2);
    
    // Attempt to call 'super' function
    sb2.init = function() {
        console.log('SubBase2.init()');
        Base2.init();
    };
    
    sb2.init();
    
    sb2.newprop = 'newprop';
    console.log('   sb2.prop1=' + sb2.prop1);
    console.log('   sb2.prop2=' + sb2.prop2);
    
    inspect(sb2, Base2, SubBase2);
    

    Initially newprop is the only property of sb2 not inherited through the prototype chain. Updating prop1 via Base2.init() keeps the property as an inherited one; however, updating or setting any property from the instance will make the property a direct one of sb2 instead of an inherited one. For example, sb2.prop1 = 'newvalue' or sb2.prop2 = 'prop2val-set-by-instance'

    So, considering all. What is wrong with just calling Base2.init() from a redefined sb2.init()?

    • Michael Prescott

      I think that just the usage of naming class style naming conventions in my example leads to confusion. As noted (many times) these aren’t classes, just objects. So, in the above, ‘prop2′ isn’t even defined until Base2’s init is called. Anyhow, I’m still questioning what problems would arise from calling Base2.init() from sb2.init(). Also, since updating the value of any inherited property from the instance is essentially eliminating the inherited property and creating a direct one, if we wanted to maintain the inherited properties we’d need to access all via setter functions.

      Oh, here’s my inspect():

      var inspect = function (obj, BaseClazzObj, SubBaseClazzObj) {
          console.log('---- Prototype Inspection ---\n');
      
          console.log('Is prototype of BaseClass: ' + BaseClazzObj.isPrototypeOf(obj));
          console.log('Is prototype of SubBaseClass: ' + SubBaseClazzObj.isPrototypeOf(obj));
          console.log('Instance is prototype of BaseClass: ' + (Object.getPrototypeOf(obj) === BaseClazzObj));
          console.log('Instance is prototype of SubBaseClass: ' + (Object.getPrototypeOf(obj) === SubBaseClazzObj));
          console.log('BaseClass is prototype of SubBaseClass: '  + (Object.getPrototypeOf(SubBaseClazzObj) === BaseClazzObj));
      
          console.log('\n---- Property Inspection ---');
          //The following example shows how to iterate over the properties of an object
          // without executing on inherit properties.
      
          var name;
          for (name in obj) {
              if (obj.hasOwnProperty(name)) {
                  console.log('   hasOwnProperty():' + name + ' = ' + obj[name]);
              } else {
                  console.log('  !hasOwnProperty():'+ name + ' = ' + obj[name]);
              }
          }
      };
      
    • Michael Prescott

      Nevermind. I think I understand now. When overriding/resetting sb2.init() and then calling Base2.init() from within it, I’m simply setting Base2’s properties after I’ve gotten properties from it. This makes it so that sb2 no longer has it’s own ‘prop1′, and ‘prop1′ is only accessible from the sb2 instance due to the prototype chain (?)

  21. Damon Black

    What are the performance implications of this pattern? From what I understand, an important reason for use of .prototype is to attach methods that are only created once, on an object’s constructor’s prototype, rather than being recreated with every call of the new keyword. Is this true of your object->object method?

    In other words when i do

    var b1 = Object.create(Bar);
    b1.init("b1");
    

    am I calling a new object method (therefore adding to memory usage) or calling up the delegation chain and using Bar.init (afaik in the ‘classical’ method i would call a pre-existing method on the prototype, not creating a brand new method).

    • With the objects-only style of code, you are still creating exactly the same objects with exactly the same [[Prototype]] linkages as you do with function-constructor style. So, the performance characteristics will basically be identical, because everything’s still the same.

      The difference with objects-only style code is that it’s vastly simpler to write and reason about. But the end result is functionally pretty much identical.

  22. I am very happy to read this. This is the type of info that needs to be given and not the accidental misinformation that’s at the other blogs. Appreciate your sharing this greatest doc.

  23. Hi,
    nice article. But… correct me if I’m wrong – this concept fails on object properties that are objects themselves.

    var A = {
    	listeners: {},
    	count: 0,
    	add: function (name){
    		this.listeners[name] = "value";
    	},
    	plus: function() {
    		this.count++;
    	}
    };
    
    
    function info(value) {
    	console.log('---- ' + value + ' ----');
    	console.log('a.listeners: ', a.listeners);
    	console.log('b.listeners: ', b.listeners);
    	console.log('a.count: ', a.count);
    	console.log('b.count: ', b.count)
    	console.log('------------------');
    }
    
    var a = Object.create(A);
    var b = Object.create(A);
    
    info('BEFORE');
    
    a.add("aaa");
    a.plus();
    
    info('AFTER');
    
    • Yes, but that would fail identically in the function-constructor style of code too. What you’re observing (correctly) is that storing data on a delegated-to object is BY-DESIGN going to be shared data with everyone else. This is exactly the same truth as if you had put a property on the “parent class (object)” that you instantiated/inherited from in function-constructor style.

    • Guido

      Why is the data shared? I totally don’t get it. :D

    • bortch

      how about that ugly way?

      var A = {
          listeners: {},
          count: 0,
          that:this,
      	add: function (name){
              var old = Object.create(this.listeners);
              this.listeners = {};
              old[name] = name;
      		this.listeners = old;
      	},
      	plus: function() {
      		this.count++;
      	}
      };
      

      displays:

      ---- BEFORE ---- (index):39
      a.listeners:  Object {} 
      b.listeners:  Object {}
      a.count:  0
      b.count:  0
      ------------------
      ---- AFTER ----
      a.listeners:  Object {c: "c", b: "b", a: "a"} 
      b.listeners:  Object {f: "f", e: "e", d: "d"} 
      a.count:  1 
      b.count:  0 
      ------------------ 
      

      -> http://jsfiddle.net/t9SZt/

  24. This is a watershed article for me on how to effectively do JavaScript “OB” programming – thanks, and good work! I will be doing a lot of re-factoring!

    Why not return this from init( ... ) so you can do the following?

    var b1 = Object.create(Bar).init('b1');
    
    • That’s a perfectly fine suggestion and I do that sometimes. I just didn’t want to muddy the article more with introducing even more different paradigms. :)

    • Tim

      I do something like:-

      new: function(who) {
          var bar= Object.create(this);
          bar.init(who);
          return bar;
          }
      [...]
      var b1= Foo.new("b1");
      
  25. Here is a possible way to use your very good ideas:

  26. Here is a possible way to use your very good ideas:

    var Vector2D = {
        create: function () {
            return Object.create(Vector2DProto);
        },
        add: function (vec1, vec2) {
            return vec1.clone().add(vec2);
        }
    }
     
    var Vector2DProto = {
        init: function (x, y) {
            this.x = x;
            this.y = y;
     
            return this;
        },
        clone: function () {
            return Vector2D.create().init(this.x, this.y);
        },
        add: function (vec) {
            this.x += vec.x;
            this.y += vec.y;
     
            return this;
        }
    }
     
    var vec1 = Vector2D.create().init(3, 4),
        vec2 = Vector2D.create().init(6, 8),
        vec3 = Vector2D.add(vec1, vec2);
     
    vec1.add(vec2);
     
    console.log(vec1, vec3)
    
  27. arrgghhh! I cannot get the code to display right!

  28. Another bad thing for this kind of JavaScript coding style is standard minify/uglify – it does not minifies properties on object, thus script footprint will be larger.

    Interesting approach but keeping in mind inheritance and footprint I don’t see any reason to use this kind of approach on anything rather than small “singleton like” object. I think “the prototype base” coding is much better approach.

  29. This is great and very clear, my concerns are memory and performance though. I’m pretty sure that

    new

    is way faster than

    Object.create

    but leaves a mess in memory for object relations. Do you have any thoughs about performance and memory Kyle?

  30. James

    Hey Kyle — I find your series awesome, but I do have an issue with the verbose’ness of many of your explanations in relation to new vs. Object.create vs. OLOO etc…

    Is it possible you can just list our the benefits, detriments in layman terms of using classical class implmentation, delegation, OLOO etc.. I find myself having to read thru 10pages of your book(s) to find a point but it gets lost in so much sugar/extraneous explanations that one can lose the point before too long … I’d much prefer you list the positives, negatives and then expand on them rather than having the reader try to identify the points you are making and where. Just my 2 cents. For example, you mention how mimicking class creating creates issues.. exactly what are these issues? When in a chain of object creations does this issue come out?

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!