Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
JavaScript, inner functions and private members
This post is part of a series called JavaScript Demystified.

In our last installment in this short JavaScript series we took a look at closures. In some of the examples, we saw functions being declared (and returned) inside other functions. The capability of declaring a function inside another one is not common to all languages — C# only added this ability in version 2.0, via anonymous delegates.

Here's an example of inner functions in use.

function printPriceLong(name, price, quantity, currency) {
	var formatCurrency = function(value) {
		return value + ' ' + currency;
	};
	return 'Item: ' + name + '\n' +
		'Unit price: ' + formatCurrency(price) + '\n' +
		'Quantity: ' + quantity + '\n' +
		'TOTAL: ' + formatCurrency(price * quantity);
}

alert( printPriceLong('100g Toblerone bar', 2.09, 3, 'USD') );
/* =>
Item: 100g Toblerone bar
Unit price: 2.09 USD
Quantity: 3
TOTAL: 6.27 USD
*/

If we try to call formatCurrency from anywhere outside of printPriceLong we are going to cause an error because formatCurrency is scoped only inside its parent function.

In this example we can also see closures in action once again. The currency value is referenced inside formatCurrency but it's declared in it's parent. It's a short-lived closure, mind you, because we are not returning that inner function. It's discarded as soon as the parent function exits.

Who said JavaScript objects can't have private members?

Developers sometimes get upset when they realize that anyone has read and write access to the fields and methods of their JavaScript objects. Most of us are used to work with languages that allow us to declare some of our object's members out of reach for the calling code. We say that these members are private and we don't want anyone changing or even seeing them.

Well, this is not exactly true. If you must have private members in your JavaScript objects, you can. Inner functions and closures will come to our rescue.

Let's build on our previous example. Let's create an OrderItem object that will hold those values (name, price, etc.) Let's assume we do not want anyone changing the object's price without changing the currency at the same time (to ensure some level of consistency.) We could code our object like this:

function OrderItem(productName, price, quantity, currency) {
	//regular properties
	this.name = productName;
	this.quantity = quantity;

	//read accessors
	this.getCurrency = function(){ return currency; };	
	this.getPrice = function(){ return price; };
	//write accessor
	this.setPrice = function(newPrice, newCurrency){
		if(typeof newPrice !== 'number' || newPrice < 0){
			throw { message:'invalid price' };
		}
		if(typeof newCurrency !== 'string'){
			throw { message:'invalid currency' };
		}
		price = newPrice;
		currency = newCurrency;
	};

	//a private function
	var formatCurrency = function(value) {
		return value + ' ' + currency;
	};
	
	//methods that need private members
	this.getUnitPriceString = function(){
		return formatCurrency(price);
	};
	this.getTotalPriceString = function(){
		return formatCurrency(price * quantity);
	};
}

OrderItem.prototype = {
	//overriding the string representation of the object
	toString: function(){
		return  'Item: ' + this.name + '\n' +
			'Unit price: ' + this.getUnitPriceString() + '\n' +
			'Quantity: ' + this.quantity + '\n' +
			'TOTAL: ' + this.getTotalPriceString();	
	}
};

That seems a bit long, but hopefully we can understand what's going on here. We are letting name and quantity be regular read/write properties but we never defined properties for price or currency. We made those two values accessible via the getPrice and getCurrency methods, respectively.

The trick here is that both getPrice and getCurrency are defined inside our constructor function so they have access to the local variables price and currency. They have access to these variables even after the constructor returns (thank you closures.)

The same can be said for the setPrice method. We will use this method when we need to change the object's price. It will force us to also provide a currency.

I'll leave the explanation of the methods getUnitPriceString and getTotalPriceString as an exercise for you.

Let's instantiate one of these objects and see it in action.

var item = new OrderItem('100g Toblerone bar', 2.09, 3, 'USD');
//public methods:
alert( item.getUnitPriceString() );
// => '2.09 USD'
alert( item.getTotalPriceString() );
// => '6.27 USD'
alert(item); //this will use the toString() method
/* =>
Item: 100g Toblerone bar
Unit price: 2.09 USD
Quantity: 3
TOTAL: 6.27 USD
*/

//changing private fields
item.setPrice(1.11, 'EUR');
alert( item );
/* =>
Item: 100g Toblerone bar
Unit price: 1.11 EUR   <-- it worked!
Quantity: 3
TOTAL: 3.33 EUR
*/

//proving that price is not a field
item.price = '5.00';
alert( item.getUnitPriceString() );
// => '1.11 EUR' <-- Gotcha, smart pants!

item.setPrice(2);
//ERROR: message = 'invalid currency'
alert( item.formatCurrency(1.23) );
//ERROR: item.formatCurrency is not a function

And what am I supposed to do with this information?

I have yet to find the need to use private members in my JavaScript objects. Maybe that's because I am not shipping any JavaScript library with complex enough objects.

I think it's nice to know that you can create those off-limits values in your object. Hopefully when the need for such thing arises, we won't just say Oh, no! Can't do that!.

What about you? Have you found a use for private members in your JavaScript code? How did you get around or implemented it?


Posted 02-24-2009 8:31 AM by sergiopereira

[Advertisement]

Comments

RhysC wrote re: JavaScript, inner functions and private members
on 02-24-2009 9:47 AM

Man, that is pretty sweet. I have never thought of either of those options.

Very simple, very cool

Scott Allen wrote re: JavaScript, inner functions and private members
on 02-24-2009 11:15 AM

For the most part no - unless I'm working on an ASP.NET AJAX extension. In that case I follow the MS  convention of prefacing "private" members with an underscore and providing get_ and set_ accessors. Supposedly closures were a perf hit in some environments so the team eschewed them in favor of the naming convention. I imagine the perf might measure differently today.

sergiopereira wrote re: JavaScript, inner functions and private members
on 02-24-2009 11:47 AM

@Scott, there's definitely a perf hit when going the closure route, including memory footprint. It might be something worth measuring if many of these objects will be alive at the same time.

Bogdan Brinzarea wrote re: JavaScript, inner functions and private members
on 02-24-2009 2:04 PM

You can also check the free chapter from my book

www.packtpub.com/.../book

sergiopereira wrote re: JavaScript, inner functions and private members
on 02-24-2009 2:44 PM

@Bogdan, that free chapter is real nice. I haven't read your book yet (I don't work with MS Ajax) but if the rest of the book is as good as that, it's gold.

DotNetShoutout wrote JavaScript, inner functions and private members - Sergio Pereira
on 02-24-2009 6:40 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Reflective Perspective - Chris Alcock » The Morning Brew #294 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #294
on 02-25-2009 3:51 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #294

DotNetKicks.com wrote JavaScript, inner functions and private members
on 02-25-2009 7:28 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

inf3rno wrote re: JavaScript, inner functions and private members
on 02-26-2009 3:09 PM

"Who said JavaScript objects can't have private members?"

Me. :-)  Using private variables in the constructor function doesn't mean that the object/class has private variables.

sergiopereira wrote re: JavaScript, inner functions and private members
on 02-26-2009 3:18 PM

@inf3rno what's your definition of private members? If you can create members that cannot be directly accessed from the object interface but can still be accessed by the object's own methods, that, for me, is exactly what private members are.

What kind of private variable are you trying to create that doesn't work using this technique?

gOODiDEA.NET wrote Interesting Finds: 2009 02.23~02.27
on 02-26-2009 9:26 PM

Web Implementing Prototype’s Array Methods in jQuery IIS 7 Compression. Good? Bad? How much? - Troubleshooting

gOODiDEA wrote Interesting Finds: 2009 02.23~02.27
on 02-26-2009 9:32 PM

WebImplementingPrototype’sArrayMethodsinjQueryIIS7Compression.Good?Bad?Howmuch?...

Web Development Community wrote JavaScript, inner functions and private members - Sergio Pereira
on 02-27-2009 12:10 AM

You are voted (great) - Trackback from Web Development Community

meisinger wrote re: JavaScript, inner functions and private members
on 02-27-2009 10:23 AM

um... i could totally be wrong here but...

the use of private variables in this case will cause a memory issue and potential slowness because the functions are declared (or defined) within the body of the OrderItem

in other words... since OrderItem defines functions, each time you "new up" an OrderItem the javascript engine will need to create the functions (e.g. getPrice, setPrice, formatCurrency)

so if you have 10 OrderItem objects, the javascript engine will need to create the six functions 10 times

you can imagine what would happen if you had 500 OrderItem objects

the only time that you don't pay the penatly is when the functions are defined within the "prototype" at which time you can't (or wouldn't) be able to have private variables

but again, since the functions are defined in the "prototype" the functions are created once and only once. so "newing up" 500 OrderItem objects is not that expensive

so while i agree that you can use private variables, i question the use of them due to the potential overhead of having them

am i wrong in this line of thinking?

sergiopereira wrote re: JavaScript, inner functions and private members
on 02-27-2009 5:52 PM

@meisinger you're correct about the memory usage. See some of the comments above. It's a tradeoff.

the birdie wrote re: JavaScript, inner functions and private members
on 10-13-2010 10:40 AM

I implement class-like objects in JS like this:

function NameOfClass(param1, param2, ...)

{

   var o = new Object;

   //private members

   var mem1;

   var mem2;

   .....

   //init code like a constructor goes here

   mem1 = 'blah';

   //public methods

  o.publicMethod1 = function()

  {

          //blah

   }

   ....

   //private methods

   function pvtMethod()

  {

       ///blah....

    }

   return o;

}

//here I create my object notice I don't use 'new'

var my_object = NameOfClass('blah', 'blah blah');

//calling public methods

my_object.publicMethod1();

I learned this from JS for web developers 2nd edition by Nicholas C. Zakas. Great book. There is acctually a lot of other methods there and explains the good and the bad. I really like this approach a lot. There is even a way to do inheritance, the downside of this method is that you cannot use instanceof keyword.

the birdie wrote re: JavaScript, inner functions and private members
on 10-13-2010 10:44 AM

sorry I forgot to add the semi-colon after the public method.....but even if you forgot it....JS let's you write code without it...I never understood that. so it should be:

o.publicMethod1 = function()

{

 //code

};

Jayesh wrote re: JavaScript, inner functions and private members
on 11-03-2010 4:00 AM

Good Explanation...

Well got it what i was searching for.

Thanks,

http://www.3cci.in

Jayesh wrote re: JavaScript, inner functions and private members
on 11-03-2010 4:02 AM

Good Explanation...

Well got it what i was searching for.

Thanks,

Henry wrote re: JavaScript, inner functions and private members
on 12-08-2010 6:31 AM

this.setPrice = function(newPrice, newCurrency){  

       if(typeof price !== 'number' || price < 0){  

           throw { message:'invalid price' };  

       }

should be

this.setPrice = function(newPrice, newCurrency){  

       if(typeof newPrice !== 'number' || newPrice < 0){  

           throw { message:'invalid price' };  

       }

sergiopereira wrote re: JavaScript, inner functions and private members
on 12-08-2010 9:19 AM

@Henry,

Thanks. Fixed now.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)