Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with:

Object.create() Improves Constructor-Based Inheritance In Javascript - It Doesn't Replace It

By Ben Nadel on

Last week, I blogged about Prototypal inheritance in Javascript, demonstrating that poor constructor logic can break the underlying inheritance mechanism. In that post, as well as in the one regarding private variables and Javascript constructors, people pointed out that Javascript's Object.create() method might be a good thing to use. I admitted that Object.create() would probably be a cleaner way of setting up my prototype chain (removing my need to create a poorly initialized object); but, having never really looked into the function, I thought it would be worth a little time.

NOTE: This is literally my first exploration of Object.create(); so, please take the following with a grain of salt.

While not supported in every browser, the Object.create() method basically takes one object and makes it the prototype of a newly created object. To demonstrate, I have created a "girl" object below; then, I use the Object.create() method to create "instances" of that girl object:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Object.create() And Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the base girl object.
  • var girl = {
  • name: "",
  • traits: {}
  • };
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create a girl instance.
  • var sarah = Object.create( girl );
  •  
  • // Set sarah's properties.
  • sarah.name = "Sarah";
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  •  
  • // Create a girl instance.
  • var tricia = Object.create( girl );
  •  
  • // Set tricia's properites.
  • tricia.name = "Tricia";
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  •  
  • // Log the girls' traits.
  • console.log( "Sarah:", sarah.traits );
  • console.log( "Tricia:", tricia.traits );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see, the girl object has two properties - name and traits. We are then using the Object.create() method to create two new instances for which girl will be the prototype. When we run the above code, we get the following console output:

Sarah: Object { age=32, weight=140 }
Tricia: Object { age=32, weight=140 }

That's not good. It appears that both of our new object instances are referencing the same "traits" property. This has to do with the way Javascript gets and sets properties in the prototype chain. Javascript will always "set" a property in the most local object; however, when "getting" a property, Javascript will traverse the entire prototype chain looking for it. The problem above arises because we are not actually setting a property; rather, we are setting a property of a property. Since traits is a complex object, our "set" doesn't count as a "local" set.

NOTE: This problem is exactly why it is critical to call your super class constructor in inheritance.

As it turns out, Object.create() is known for being somewhat lacking in the "initialization" department; as such, it is recommended that an init() method be added to an object such that after it is put in the prototype chain, it can be more fully initialized. Let's try that:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Object.create() And Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the base girl object.
  • var girl = {
  •  
  • // I am the initialize method.
  • init: function( name ){
  •  
  • // Store the name.
  • this.name = name;
  •  
  • // Create a local copy of the traits object so that
  • // multiple instances don't share the same object.
  • this.traits = {};
  •  
  • // Return this object reference.
  • return( this );
  •  
  • },
  •  
  • // Properties.
  • name: "",
  • traits: {}
  •  
  • };
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create a girl instance.
  • //
  • // NOTE: Be sure to call INIT() on the object, otherwise
  • // it will not be property initialized.
  • var sarah = Object.create( girl ).init( "Sarah" );
  •  
  • // Set sarah's properties.
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  •  
  • // Create a girl instance.
  • //
  • // NOTE: Be sure to call INIT() on the object, otherwise
  • // it will not be property initialized.
  • var tricia = Object.create( girl ).init( "Tricia" );
  •  
  • // Set tricia's properites.
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  •  
  • // Log the girls' traits.
  • console.log( "Sarah:", sarah.traits );
  • console.log( "Tricia:", tricia.traits );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see here, our girl object still has the two properties - name and traits; but, this time, it also has the init() method. And, you'll see that when we use Object.create() to generate two "instances" of girl, we immediately call the init() method to initialize the object. This time, when we run the above code, we get the following output:

Sarah: Object { age=30, weight=125 }
Tricia: Object { age=32, weight=140 }

Excellent! This time, each of the girl instances is clearly using its own, local copy of the traits property.

But, this code looks a little bit junky, right? I mean, our base girl object has to, essentially, define its properties twice - once in the object literal and once in the init() method. This is definitely not an adherence to the DRY principle (Don't Repeat Yourself). You might be tempted to remove the properties from the object literal and just put them in the init() method; however, you can't do that because, in order to use it on its own, the base girl object would have to be both defined (object literal) and initialized (init()). In that case, you're kind of replacing one violation of DRY with another. Plus, that starts to look like "new"-based inheritance, which I assume we're trying to avoid.

So far, we've only looked at one level of inheritance; but, what happens when we introduce a second level of inheritance? What happens if we want our "girl" object to, itself, be an instance of another object - in this case, person.

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Object.create() And Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the person object.
  • var person = {
  •  
  • // I am the initialize method.
  • init: function( name ){
  •  
  • // Store the name.
  • this.name = name;
  •  
  • // Return this object reference.
  • return( this );
  •  
  • },
  •  
  • // Properties.
  • name: ""
  •  
  • };
  •  
  •  
  • // Create the girl object. We can't relaly call init() at
  • // this point because we aren't really creating an instance
  • // of "Person"; rather, we are just creating an object which
  • // will, itself, be created.
  • var girl = Object.create( person );
  •  
  • // Provide the girl with an init method.
  • girl.init = function( name ){
  •  
  • // First, initialize this object as a person.
  • person.init.call( this, name );
  •  
  • // Create a local copy of the traits object so that
  • // multiple instances don't share the same object.
  • this.traits = {};
  •  
  • // Return this object reference.
  • return( this );
  •  
  • };
  •  
  • // Propeties.
  • girl.traits = {};
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create a girl instance.
  • //
  • // NOTE: Be sure to call INIT() on the object, otherwise
  • // it will not be property initialized.
  • var sarah = Object.create( girl ).init( "Sarah" );
  •  
  • // Set sarah's properties.
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  •  
  • // Create a girl instance.
  • //
  • // NOTE: Be sure to call INIT() on the object, otherwise
  • // it will not be property initialized.
  • var tricia = Object.create( girl ).init( "Tricia" );
  •  
  • // Set tricia's properites.
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  •  
  • // Log the girls' traits.
  • console.log( "Sarah:", sarah.traits );
  • console.log( "Tricia:", tricia.traits );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see, this time, we are creating a person object. Then, we create our girl object as an "instance" of the person object. We can't however, call init() on the girl object since we don't have a name - there's nothing to initialize it with. As such, we just leave it as an uninitialized object until the init() method on the girl is called. At that point, we call the init() method on the person object to fully initialize it's person aspects and it's girl aspects.

And, when we run the above code, we get the following output:

Sarah: Object { age=30, weight=125 }
Tricia: Object { age=32, weight=140 }

This works.

We still have the duplication of properties; but, more frustratingly, we now find ourselves in a weird chicken-and-egg dilemma. We can't init() the girl object until after the init() method is defined; and, we can't define the init() method until after the girl is created.

And, we are still left in a situation where the girl object has to be both defined and initialized. This just kind of leaves a bad taste in my mouth. Not to mention the fact that this is starting to look more and more like "traditional" Prototypal inheritance - which I assume is what Object.create() is meant to avoid.

Ok, so what if we just create a person object and a girl object and don't link them until the init() method is called? At least this way, both the person object and the girl object are created in a uniform way.

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Object.create() And Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the person object.
  • var person = {
  •  
  • // I am the initialize method.
  • init: function( name ){
  •  
  • // Store the name.
  • this.name = name;
  •  
  • // Return this object reference.
  • return( this );
  •  
  • },
  •  
  • // Accessor.
  • getName: function(){
  • return( this.name );
  • },
  •  
  • // Properties.
  • name: ""
  •  
  • };
  •  
  •  
  • // Create the girl object. This time, we are not creating
  • // any direct relationship between person and girl.
  • var girl = {
  •  
  • // I am the initialize method.
  • init: function( name ){
  •  
  • // First, initialize this object as a person.
  • person.init.call( this, name );
  •  
  • // Create a local copy of the traits object so that
  • // multiple instances don't share the same object.
  • this.traits = {};
  •  
  • // Return this object reference.
  • return( this );
  •  
  • },
  •  
  • // Properties.
  • traits: {}
  •  
  • };
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create a girl instance.
  • var sarah = Object.create( girl ).init( "Sarah" );
  •  
  • // Set sarah's properties.
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  •  
  • // Create a girl instance.
  • var tricia = Object.create( girl ).init( "Tricia" );
  •  
  • // Set tricia's properites.
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  •  
  • // Log the girls' traits.
  • console.log( sarah.getName(), sarah.traits );
  • console.log( tricia.getName(), tricia.traits );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see, both the person and the girl object are being created in the same way. And, while the uniformity is attractive, this approach is a complete disaster, leaving us with code that doesn't even run. Trying to run the above code raises the following Javascript exception:

sarah.getName is not a function

The problem here is that the class methods of the person object - getName() - never get linked to the girl object because we never actually created girl as an instance of person. In essence, we never added person to the girl's prototype chain.

Unless I am missing something very subtle, it appears that Object.create() is not that useful. It seems to create a lot of problems; and, in an attempt to solve those problems, our solutions start to look more and more like new/constructor-based instantiation and inheritance.

I think people use the Object.create() approach because they are stuck between two worlds - on one hand, they want to make use of inheritance; on the other hand, they have some irrational fear of constructor functions. So they try really hard to avoid constructors; and, in doing so, they end up creating functions that look and act like constructors, but with a lot of duplicated effort and without any of the contraints that make constructors awesome.

Don't Lose Hope - Object.create() Is Awesome

Now, that's not to say that I don't see a place for the Object.create() method. In fact, I see it as being awesome for constructing prototype chains in the context of constructor-based inheritance. To demonstrate, take a look at this code:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Object.create() And Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the person constructor.
  • function Person( name ){
  •  
  • // Store the property.
  • this.name = name;
  •  
  • }
  •  
  • // Set up the class methods.
  • Person.prototype.getName = function(){
  •  
  • return( this.name );
  •  
  • };
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I am the girl constructor.
  • function Girl( name ){
  •  
  • // Call the super constructor.
  • Person.call( this, name );
  •  
  • // Create the traits property.
  • this.traits = {};
  •  
  • }
  •  
  • // Extend the person prototype using Object.create(). Since
  • // we are not actually creating an instance of person, we
  • // don't have to worry about initialization - we simply
  • // extend the Prototype of the Person and then we'll worry
  • // about initialization later.
  • Girl.prototype = Object.create( Person.prototype );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create a girl instance.
  • var sarah = new Girl( "Sarah" );
  •  
  • // Set sarah's properties.
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  •  
  • // Create a girl instance.
  • var tricia = new Girl( "Tricia" );
  •  
  • // Set tricia's properites.
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  •  
  • // Log the girls' traits.
  • console.log( sarah.getName(), sarah.traits );
  • console.log( tricia.getName(), tricia.traits );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see, we are defining our object constructors - Person and Girl. Then, we are using the Object.create() function as a means to link the two prototypes together, creating a single prototype chain. Not only does this require much less code, I think it's a much cleaner implementation of inheritance. There's no ambiguity about what the objects are doing - are they constructors, are they object instances? It's very clear what objects are meant to do what.

And, when we run the above code, we get the following output:

Sarah Object { age=30, weight=125 }
Tricia Object { age=32, weight=140 }

To me, this is the best of both worlds. We use the Object.create() method to create a very clean prototype chain; then, we use our constructor functions to initialize the objects in the context of that prototype chain. We have zero duplication of properties and no ambiguity.

I hope this post doesn't come across as me hating on Object.create(). In fact, I have recently become a huge fan of Object.create() for creating prototype chains. What I don't see as being useful in any way at all is the use of Object.create() as a means to implement the entire inheritance mechanism. It is, however, definitely a very elegant way of implementing a small portion of the overall construtor-based prototypal inheritance approach. But, it's only elegant if you are still using constructors.




Reader Comments

Well, I'm not sure why anyone would really want to use Object.create as full on inheritance mechanisms for structured types, but I'm glad that you've come to appreciate the elegance that it brings to the definition of constructors. As I've pointed out on the last post, you need more than just Object.create when setting up the prototype chain.

Now, please read my book "More Intuitive Javascript" at http://jay.ngspinners.com for lots more secrets like this, and start using the Jay standard library's small little type definition utils.

Thanks

Tim

@Drew,

I was not aware of performance differences. What are you referring to in terms of "new" being a hack? I didn't see that in the link you provided. I think "new" is awesome :D

@Tim,

I know this isn't across the board; but, I feel like I have many times seen people hail Object.create() as a replacement for a the "broken" inheritance mechanism in Javascript. I think they work best when put hand-in-hand; we're not talking replacement - we're talking about synergy (winces at using cliched term) :).

I'll check out your book :)

@Ben,

I'm sure you're right about people sometimes do to try and get away from what they feel is a broken inheritance mechanism.

I'm interested to know why you think people regard it as broken, if you feel like blogging about that sometime.

My main motivation for the Jay project was to discover how we can better understand the aspects of the language that are or appear to be broken. Through suggesting a certain approach to typing I've hopefully made it more apparent that the language's attempt at prototypal inheritance is not beyond repair nor is it even ugly, you just need to know how to understand and use it.

Let me know what you think of it. ;-)

Tim

@Ben,

I feel like I need to skim over the ECMASCRIPT references to see if I'm even correct here. From what I understand, classical inheritance was added to the language after initial implementation. It does a lot of prototype/constructor setting internally to make things work with the Prototypal nature of the language.

@Ben @Tim,

I concur with Ben, I think Object.create is somewhat clearer than new. For instance, an object with methods and methods inherited via prototype chain can not be accessed in an obvious way. I say obvious in that I find it difficult to explain to others why $.each() and $('blah').each() are not the same method.

The alternative is highly unattractive, I admit. $('blah').each() and $('blah').prototype.each

@Tim,

"you just need to know how to understand and use it."

I think that is really what it comes down to. Understanding prototypal inheritance is a very strange thing. Technically, it's actually really simple. But, somehow, wrapping your head around it can be extremely tricky... and I can't even tell you why. I was *taught* Prototypal inheritance in college 10 years ago. But, I have only felt very comfortable with it recently. In fact, as you know, my use of Object.create() in a prototype context *just* really formalized in the last week.

I think people lean on Object.create() to have it do more than it should because they are really looking for something that is simple. But, really, it's not any more simple. And, as @Drew points out, a manually implementation of Object.create() uses "new" under the hood anyway.

@Ben,

Just FYI, from Papa Crockford's "JavaScript: The Good Parts", pp. 22-3:

  • if (typeof Object.create !== 'function') {
  • Object.create = function (o) {
  • var F = function () {};
  • F.prototype = o;
  • return new F();
  • };
  • }
  • var another_stooge = Object.create(stooge);

With this script, you can remove subjunctive clause "While not supported in every browser," near the beginning of your article, above. Note that it leaves the browser-native implementation, if any, untouched.

@Ben,

Of course, the stooges line is a usage example, not part of the script! But that's not why I'm reposting:

John Resig is leaving Mozilla and largely leaving jQuery! Just posted today on ejohn:

http://ejohn.org/blog/next-steps-in-2011/

He'll continue to work on jQuery mobile and still has a few speaking engagements, so he'll still be around. Stunning news, even so.

@WebManWalking,

Oh wow, good for him. Though, it sounds like he'll still be working on jQuery - just not Mozilla stuff.

@Ben,

Looking back over previous articles, I see now that you already gave similar window.objectCreate code in "Your Javascript Constructor Logic May Break Prototypal Inheritance", and that Asen already gave similar window.create code in "Private Variables Do Not Necessarily Break Prototypal Inheritance In Javascript".

The main benefit of Crockford's version would therefore have to be that he defines it in the Object object, and only if undefined, allowing subsequent coding of the standard method name.

@Ben:

Well, I tried to apologize for beating an already-sufficiently-beaten dead horse. But in my rationalization that at least there was something new in Crockford's approach, I appear to have beaten it some more.

:-)

I don't see any advantages of the function constructor method as you suggest.

In your 3rd code example if you remove the girl and person object literal properties, then the setup is equivalent to the function method. The girl and person objects are constructors, and the sarah and tricia objects are instances.

"ambiguity about what the objects are doing - are they constructors, are they object instances?"

You can distinguish a constructor object because it has its own init method, and no object literal properties.

"our base girl object has to, essentially, define its properties twice - once in the object literal and once in the init() method."

The girl constructor object literal properties are removed, just as they don't exist in a function constructor.

"in order to use it on its own, the base girl object would have to be both defined (object literal) and initialized (init())."

Function constructors are not used on their own so why object constructors?

"we are still left in a situation where the girl object has to be both defined and initialized"

It doesn't need initialising since it is a constructor.

"it appears that Object.create() is not that useful."

On the contrary, it removes the need for the function constructor method, and may simplify Javascript. Object.create()is also better since "functional" inheritance like Girl.prototype=Object.create(Person.prototype), is replaced by girl=Object.create(person), which doesn't mention confusing prototypes, and which has a similar format to instance creation, e.g. sarah=Object.create(girl).init('Sarah'). The format of sarah=new Girl("Sarah") is completely different to that of Girl.prototype... above, and more complex.

Less is more, if enough.

What should functions be anyway? It seems twisted that they can both create an object and yet also be part of an object as a method. The creator can be part of the created? Should stand alone (non-constructor) functions always be made methods instead? For many reasons, including simplification, functions may be best only as object methods.

If the Crockford prototype function is modified slightly then Object creation can include basic instantiation too, and further simplify matters.

  • Object.creator = function(o) {
  • var initArgs = Array.prototype.slice.call(arguments,1)
  • function F() {
  • if((typeof o.init==='function') && initArgs.length) {
  • o.init.apply(this,initArgs)
  • }
  • }
  • F.prototype = o
  • return new F()
  • }

Then your 3rd code example above could look nicer. Instead of Object.create(girl).init("Sarah") you can use Object.creator(girl, "Sarah") and also lose the need for return(this) in the two init methods.

  • // Constructor
  • var person = {}
  • person.init = function(name) {
  • this.name = name
  • }
  •  
  • // Constructor
  • var girl = Object.creator(person)
  • girl.init = function(name, age, weight) {
  • this.traits = {age:age, weight:weight}
  • person.init.call(this, name)
  • }
  •  
  • // Instance
  • var sarah = Object.creator(girl, 'Sarah', 30, 125)

This looks better to me and simpler than using function constructors, as in your 5th code example. Object.creator is used for both constructor and instance creation, for the prototype chain, and for initialisation.

@John,

I suppose it just comes down to what you are used to / prefer. For me, it's just easier to think about representations rather than instances. To each their own.

Hi Ben,

thanks for the article. I've got one question, though. Why not just use this?

Girl.prototype = Person.prototype;

The Person object sets up all its members in the constructor class so there should be no shared members which could cause a conflict.

Thanks
Frank

@Frank,

The problem with setting one prototype directly to the other is that changes to either of them will affect the other one. So, if the Girl's prototype points to the Person's prototype, then any additions to Girl.prototype will also be additions to Person.prototype. You don't want changes to go up-chain, only down-chain.

Using Object.create() to link the prototypes allows the down-chain object (Girl) to modify its prototype without augmenting the up-chain object (Person).

I feel it's a mistake to mix new and Object.create(). They both need to do two things 1) establish the prototype chain and 2) initialize the instance data.
The example you used has nothing to inherit; its all instance data. The equivalent of your first example is:

  • function girl() {};
  • girl.prototype = {
  • name: "",
  • traits: {}
  • };
  •  
  • var sarah = new girl;
  •  
  • // Set sarah's properties.
  • sarah.name = "Sarah";
  • sarah.traits.age = 30;
  • sarah.traits.weight = 125;
  •  
  • // Create a girl instance.
  • var tricia = new girl;
  •  
  • // Set tricia's properites.
  • tricia.name = "Tricia";
  • tricia.traits.age = 32;
  • tricia.traits.weight = 140;
  •  
  • // Log the girls' traits.
  • console.log( "Sarah:", sarah.traits );
  • console.log( "Tricia:", tricia.traits );

It isn't until you introduce the getName() method that inheritance is of any use. The final example could be written:

  • var Person = Object.create({}, {
  • getName: {value: function() { return this.name; }
  • },
  • init: {value: function(name) {
  • this.name = name;
  • return this;
  • } }
  • });
  •  
  • var Girl = Object.create(Person, {
  • init: {value: function(name, age, weight) {
  • Person.init.call( this, name );
  • this.traits = {
  • age: age,
  • weight: weight
  • };
  • return this;
  • } }
  • });
  •  
  • var sarah = Object.create(Girl).init("Sarah", 30, 125);
  • var tricia = Object.create(Girl).init("Tricia", 32, 140);
  •  
  • console.log( sarah.getName(), sarah.traits );
  • console.log( tricia.getName(), tricia.traits );

There are some lightweight objects out there that can be used as the base class of an Object hierarchy that make for some very clean syntax.
I would recommend looking at: http://uxebu.com/blog/2011/02/23/object-based-inheritance-for-ecmascript-5/

one thing that many people forget to do is to reset the constructor property on the inherited object to make it point to the correct constructor.

Object.create has a second parameter that's essentially designed to facilitate inheritance. Check this out: http://stackoverflow.com/questions/2709612/using-object-create-instead-of-new/2709811#2709811

You'd basically make Girl and Person factory functions that return object literals, and then pass results therefrom into Object.create. The factory functions could easily take parameters that handle initializing the names or whatever.

Unfortunately this would only work on browsers that implement create, and getting it compatible with IE7 would be a bit hacky.

Constructors still seem the best bet for my money.

Very helpful set of articles. I am a c++ man delving into javascript inheritance for the first time and have settled on your suggestion. I don't think I fully understand all the advantages and disadvantages of each pattern yet but I learn a lot better coding than I do reading and this pattern seems to be concise and give me everything I need to get on with.

One question for anyone, I hope it's not too off topic. Following the DRY principle ( or as I have always said, 'less is more' ), I am using constructor parameters as private members. e.g.

  • function Person( pName ){
  •  
  • this.nameGet = function(){ return pName; }
  • this.nameSet = function( pNameSetter ){ pName = pNameSetter; }
  •  
  • }

instead of...

  • function Person( pName ){
  •  
  • var name = pName;
  •  
  • this.nameGet = function(){ return name; }
  • this.nameSet = function( pName ){ name = pName; }
  •  
  • }

It feels evil but it's short and I'm not keeping the same data in 2 places at once so I guess it's clearer. I see no logical reason not to do it. Please dissuade me from my evil ways. I'm not used to all this power and am sure to abuse it with tragic consequences.

@Pangus,

to understand the reasoning behind the design patterns I can recommend the book "Pro JavaScript Design Patterns" which starts out building simple classes, then adding encapsulation, inheritance and so forth. The authors are showing the different ways of emulating certain language features that JS is currently lacking. For example, encapsulation is modeled using closures - just like in your example. I can also recommend the videos from Douglas Crockford. Part 3 talks about design patterns but it takes a while to grok it.

Your code behaves a bit different depending on how you use it. Remember that JS is not strongly typed and that objects are passed by reference. Take this example:

var o1 = {first:'Alice'};
var o2 = {first:'Bob'};

var p1 = new Person(o1); // name === pName
p1.setName(o2); // v1: name === pName, v2: name !== pName

Generally, I don't use a separate variable for the constructor arguments. I just use them as private variables.

Frank

@Frank,

Thanks for the speedy response and the reading recommendations.

I'm not sure I see what you're getting at in the example. However, your mention of objects passing by reference and trying to work out your example got me thinking...

If I pass an object as a parameter, it can subsequently be altered from elsewhere and is therefore not well encapsulated.

If I copy the properties of the object into variables declared using var in the constructor, they cannot be altered from elsewhere and are therefore well encapsulated.

Is that what you were trying to tell me? I have a feeling your example was more subtle than that.

Hi guys. Maybe is too late (and maybe I'm wrong), but I think the method defineProperty solves your problem without any complex pattern:

  • var girl = {
  • name: "",
  • traits: {}
  • };
  •  
  • var sarah = Object.create( girl );
  • sarah.name = "Sarah";
  • Object.defineProperty(sarah, "traits", { value: { age: 30, weight: 125 }, writable: true, enumerable: true, configurable: true });
  •  
  • var tricia = Object.create( girl );
  • tricia.name = "Tricia";
  • Object.defineProperty(tricia, "traits", { value: { age: 32, weight: 140 }, writable: true, enumerable: true, configurable: true });
  •  
  • console.log( "Sarah:", sarah.traits );
  • console.log( "Tricia:", tricia.traits );

I know this post is old, but for those that are finding it now a days there is a way to override properties without an init method. Object.create takes a second param that it uses to override properties.

  • var sarah = Object.create( girl, {
  • traits:{
  • value:{
  • age:30,
  • weight:125
  • }
  • }
  • });
  •  
  • var tricia = Object.create( girl, {
  • traits: {
  • value:{
  • age:32,
  • weight:140
  • }
  • }
  • });

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

http://jsbin.com/lakehoso/1/edit?js,console

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

http://jsbin.com/lakehoso/1/edit?js,console

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = {
name: "",
traits: { age: 0, weight: 0 }
};

var sarah = Object.create( girl );

// Set sarah's properties.
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};


// Create a girl instance.
var tricia = Object.create( girl );

// Set tricia's properites.
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

// Log the girls' traits.
console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = {
name: "",
traits: { age: 0, weight: 0 }
};

var sarah = Object.create( girl );

// Set sarah's properties.
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};


// Create a girl instance.
var tricia = Object.create( girl );

// Set tricia's properites.
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

// Log the girls' traits.
console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = {
name: "",
traits: { age: 0, weight: 0 }
};

var sarah = Object.create( girl );

// Set sarah's properties.
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};


// Create a girl instance.
var tricia = Object.create( girl );

// Set tricia's properites.
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

// Log the girls' traits.
console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = { name: "", traits: { age: 0, weight: 0 } };

var sarah = Object.create( girl );
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};

var tricia = Object.create( girl );
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = { name: "", traits: { age: 0, weight: 0 } };

var sarah = Object.create( girl );
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};

var tricia = Object.create( girl );
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

I'm a noob learning JS and I was very excited to come across object.create; it ticks all my boxes of simplicity and object inheritance, but i stumbled across this post and my heart sank. I did not want to touch 'this' or 'new' keywords as it's not a classical OO language.

But i managed to get your code working by forcing the complex object literal into the parent object, which kind of makes sense as we are forcing the parent to have set data types that can be inherited. Your original proposition of traits: {} assumes the child can dump complex object literals onto the parent, when in real-life it should be the other way around, ie parents dictate form and structure for the child to inherit.

var girl = { name: "", traits: { age: 0, weight: 0 } };

var sarah = Object.create( girl );
sarah.name = "Sarah";
sarah.traits = {age: 30, weight: 200};

var tricia = Object.create( girl );
tricia.name = "Tricia";
tricia.traits = {age: 60, weight: 400};

console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I note Arlo's comment also fixes the issue using defineProperty, good stuff.

This is even cleaner:

var girl = {
name: "",
traits: {}
};

var sarah = Object.create( girl );

// Set sarah's properties.
sarah.name = "Sarah";
sarah.traits = {age : 30, weight : 125};

// Create a girl instance.
var tricia = Object.create( girl );

// Set tricia's properites.
tricia.name = "Tricia";
tricia.traits = {age : 60, weight : 225};

// Log the girls' traits.
console.log( "Sarah: ", sarah.traits );
console.log( "Tricia: ", tricia.traits );

I find that this article:
http://javascript.info/tutorial/pseudo-classical-pattern
is beginner friendly and shows how to implement pseudo classical inheritance pattern with just two functions one of which is the same good old Object.create, just with a different name.

The article also mentions some pitfalls for prototype assignments and shows a technique how to safely implement calling "base class" constructors from "child class" constructors.

Essentially, the author of that article seems to have come to the same conclusions: it's convenient and straight-forward to use "new" for object instances, but Object.create (which is called "inherit" in that article) is used only to create class-like relations between objects. Such solution works better for those who come from classical OOP languages.

Object.Create() works great if you want to change primitive data types as that doesn't affect the base class, e.g.

var base = {
age: 100
};

var john = Object.create( base );
john.age = 50;

var sue = Object.create( base );

console.log( john ); //Object {age: 50}
console.log( sue ); // Object {age: 100}

If we use reference types, then any changes are reflected in subsequent children:

var base = {
oAge: {age:100} //complex data type
};

var john = Object.create( base );
john.oAge.age= 50;

var sue = Object.create( base );

console.log( john ); // john age is 50
console.log( sue ); // sue age is also 50 ?!

WORK-AROUND

var base = {
oAge: {age:100}
};

var john = Object.create( base );
john.oAge = Object.create( base.oAge );
john.oAge.age= 50;

var sue = Object.create( base );

console.log( john ); // john age is 50
console.log( sue ); // sue age is also 100

Ben, thanks for posting this. I've been teaching myself the finer points of JS and really needed a good understanding of Object/Class creation. This post was quite helpful.