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 the jQuery Conference 2010 (Boston, MA) with:

Private Variables Do Not Necessarily Break Prototypal Inheritance In Javascript

By Ben Nadel on

After blogging this morning about how poor constructor logic can break prototypal inheritance in Javascript, I wanted to clarify that I was not trying to imply that the use of "private" variables breaks prototypal inheritance. At least, not necessarily. In my previous post, my "poor choice" demo did include private variables; however, this was only to create a context in which one might return an object literal from a constructor. Private variables are totally fine in the context of the prototype chain so long as your object's API is still this-scoped.

If you want to see a use of private variables that does break prototypal inheritance, take a look at my previous post. But, below, I'll show you a use of private variables that keeps the initialization chain in tact; which, in turn, allows for proper inheritance.

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Constructor Logic Is Critical For Prototypal Inheritance</title>
  • <script type="text/javascript">
  •  
  •  
  • // I am the person constructor.
  • function Person( name ){
  •  
  • // Create a **PRIVATE** property for name.
  • var name = arguments[ 1 ];
  •  
  • // Create a **PRIVATE** property for traits.
  • var traits = {};
  •  
  •  
  • // Create a method for accessing the name.
  • //
  • // NOTE: Since this method is this-scoped, each
  • // *intialized* instance will get its own copy.
  • this.getName = function(){
  • return( name );
  • };
  •  
  •  
  • // Create a method for accessing / mutating the
  • // traits collection.
  • //
  • // NOTE: Since this method is this-scoped, each
  • // *intialized* instance will get its own copy.
  • this.trait = function( name, value ){
  •  
  • // Check to see if we are getting or setting
  • // the given trait for this person.
  • if (arguments.length == 2){
  •  
  • // Set the trait.
  • traits[ name ] = value;
  •  
  • // Return this object.
  • return( this );
  •  
  • } else {
  •  
  • // Return the given triat.
  • return( traits[ name ] );
  •  
  • }
  •  
  • };
  •  
  •  
  • // Create a way to access the traits (for debugging).
  • //
  • // NOTE: Since this method is this-scoped, each
  • // *intialized* instance will get its own copy.
  • this.getTraits = function(){
  • return( traits );
  • };
  •  
  • }
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I am the girl contructor.
  • function Girl( name, age, weight ){
  •  
  • // Call the super constructor to initiate base class.
  • Person.call( this, name );
  •  
  • // Store the additional properties.
  • this.trait( "age", (age - 5) );
  • this.trait( "weight", (weight - 10) );
  •  
  • }
  •  
  • // Extend the Person class.
  • Girl.prototype = new Person();
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Create some girl instances.
  • var sarah = new Girl( "Sarah", 32, 115 );
  • var tricia = new Girl( "Tricia", 30, 125 );
  •  
  • // Log the girls' traits.
  • console.log( "Sarah:", sarah.getTraits() );
  • console.log( "Tricia:", tricia.getTraits() );
  •  
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Left intentionally blank. -->
  • </body>
  • </html>

As you can see, the Person() constructor declares two private variables - name and traits. But, the reason that the inheritance works is because the API for the object - getName(), trait(), getTraits() - is still declared in the "this" scope. In doing so, the sub-class can still be assigned unique methods that point to unique members as a byproduct of the super-class' constructor.

When we run the above code, we get the following console output:

Sarah: Object { age=27, weight=105 }
Tricia: Object { age=25, weight=115 }

As you can see, both Girl() instances are clearly using a different set of private variables. The initialization chain worked!

I am not personally a fan of lexically-scoped private variables. Frankly, I'm not that good a programmer. I much prefer convention-based private variables (ie. members that start with an underscore "_"). But, I just wanted to clarify that lexically-scoped private variables don't necessarily break prototypal inheritance. Rather, proper initialization chains are based on the way an object's API is architected.




Reader Comments

While not the point of this post, I thought it might be interesting to point out that in this configuration, the sub-class instances do not have direct access to the super-class private variables; instead, the sub-class instances may only access their super-class variables using the inherited (this-based) API. So, as an example, the Girl() instance cannot access the "name" variable except through the this.getName() method.

"Frankly, I'm not that good a programmer."

That made me smile. I think most of us feel this way, Ben. But in reality, I think what makes a good programmer is not really how much you know, rather how much you strive to be the best at what you do and how you approach learning new things.

From my perspective, you are a good programmer because you analyze things to understand them correctly so that you properly implement it in code.

@TJ,

Ha ha, thanks :) I definitely love to figure all this stuff out! And, prototypal inheritance is definitely a bit of a mind-bender! Just trying to make baby steps.

I just know that at some point, one day...maybe way down the road...you're going to start using 'woman' vs. 'girl' in your examples ;)

Just teasing my boy. Oh wait, I mean, my man.

Cheers.

Hi Ben.

The problem with this patter is the memory usage. Your `Person' constructor is factory constructor. It adds three instance methods.

// Extend the Person class.
Girl.prototype = new Person();

Now, `Girl.prototype' object has three methods: `getName', `trait' and `getTraits'.

In your `Girl' constructor you have called `Person' constructor again. This time you have called with instance object created trough: `new Girl'. So you recreate those three methods again. Your prototype chain looks:

null
^
|
|
Object.prototype = {};
^
|
|
Person.prototype = {};
^
|
|
Girl.prototype = {
treat : function,
getName : function,
getTreats : function
};
^
|
|
Girl.instance = {
treat : function,
getName : function,
getTreats : function
};

Personally I would not use such a pattern or at least I would create extending pattern with intermediate object in prototype chain instead of calling parent constructor directly.

@Steve,

It's funny you mention that - I though I had been using "women" for a while??? Why did I stop? I can't remember. Honestly, I think there's something subtle that's hard to type about it. Maybe because I can't just add "S" for plural. I'll try to stay focused :)

@Asen,

I will agree with you that using something like:

  • Girl.prototype = new Person()

... is not the cleanest approach. In my other post, someone pointed out that I should be using Object.create() to define the prototype chain so that I am not actually having to call the super-class constructor.

I agree with this; years and years ago, I was taught to use the "new" approach and I guess old habits die very hard :)

That said, the way you construct the prototype chain does not have much of an affect on the choices made in the constructor functions themselves. And, the point of the post is to show that one can use private variables (locally scoped constructor var's) without breaking inheritance.

@Ben,
Yep `Object.create' is possible approach, but it is not supported by old engines which implements ECMA-262 3rd edition.

As a fallback of `Object.create' you could use factory pattern as like this:

var create = (function () {
function F(){}
return function (proto) {
F.prototype = proto;
return new F;
};
})();

Maybe I'm missing something, but by creating the functions on the object itself instead of the prototype, you've lost a major reason for going with prototypical inheritance and shouldn't you ar that point adopt Crockford's module pattern? Your approach feels like the worst of both worlds to me.

@Asen,

I finally did an exploration of Object.create(). Just to get my feet wet. I am really liking it for creating the prototype chain in the context of constructor-based inheritance.

http://www.bennadel.com/blog/2184-Object-create-Improves-Constructor-Based-Inheritance-In-Javascript-It-Doesn-t-Replace-It.htm

@Matt,

I 1,000% agree with you! I am a major fan of the use of prototype to store methods - as you say, that *is* the reason that the prototype is so awesome. I did not mean to imply that I would use private variables (and the necessary closures) - I was only trying to demonstrate that private variables don't necessarily break prototypal inheritance.

I agree with the title of this post 100%. I have noticed that many people have found many different ways to implement private members in JavaScript, but most of the time, the public getters and setters are defined for each instance. I recently wrote an article which shows how to give prototypal functions access to private members by using code similar to what you have in your example: http://gotochriswest.com/blog/2011/05/04/private-variables-in-javascript/

I was experimenting for some time with different patterns, but neither of them so far seems solid to me. In this case I think Matt is right. You do not visibly break prototypal-inheritance, but on practice you do. Unless I miss something important here, the whole point of having prototypal inheritance gets completely wiped out with this pattern in first place. Don't you think?

Using this implemenation of inheritance, can I override a parent function in a derived class and then call the parent function from the overriding function?

If so, what would that look like?

The Girl class is not actually related to person in any way, calling

  • Girl.prototype = new Person();

is superfluous since you are doing

  • Person.call( this, name);

. which shadows everything in the prototype.

If you remove the call, the Girl class cannot use its prototype (I.E no inheritance) because the closures in its prototype are tied into one-time environment instead of being available for generic use. You can see that every girl you create will share the same state instead of encapsulating their own data.