Private Variables in JavaScript

Ok, enough of this social/ranting stuff. Time to write something vaguely technical.

I have a love-hate relationship with JavaScript. I think anyone who works with it does. Sometimes it just doesn’t do what you expect, and it’s certainly different.

One trick, especially for people from real Object-Oriented languages like Java, Ruby, or let’s even say PHP 5, is the lack of access control. When everything is an object, the inability to hide certain values can become a problem.

Say, for example, you create an object that represents a product you sell, and you want to use one of your part numbers to identify the object. Let’s say the format for your part number is 1234-56. You might do something like…

function Product (){
  1.     this.partNum;
  2.     this.setPartNum = function( num ){
  3.         if( partNumRegex.match(num)){
  4.             this.partNum = num;
  5.             returntrue;
  6.         }else{
  7.             returnfalse;
  8.         }
  9.     }
  10. }

You’re expecting the rest of your team to be respectful and use the Product.setPartNum() method, which should stop them from using an illegally formatted part number. (partNumRegex is left as an exercise to the reader.)

But what’s stopping them from doing this?

var jacket = new Product;
  1. jacket.partNum = ‘1234’;

Now when they call your Ajax-driven getProductData() method, they’ll get an error. Had they used the setPartNum() method, they would’ve seen the error much earlier.

One trick to JavaScript is that variables are lexically scoped. Basically, functions use the value of a variable where they are defined, not where they’re executed, for example (or just read a better article):

var a = 1;
  2. function globalA(){
  3.     alert(a); //1
  4. }
  6. function localA (){
  7.     var a = 2;
  8.     alert(a); //2
  9. }

So how does this help? Well, you can effectively hide values in a deeper scope. Instead of using the this keyword, just define new variables within your function:

function Product (){
  1.     var partNum;
  2.     this.setPartNum = function(num){
  3.         // Fancy checking logic
  4.     }
  5.     this.getPartNum = function(){
  6.         return partNum;
  7.     }
  8. }
  10. var tshirt = new Product;
  11. tshirt.partNum = 7;
  12. tshirt.getPartNum(); // null

This same thing can apply to private methods. Don’t want the new guy calling superSecretInternalMethod()? One common practice is to start private methods with an underscore, but a better way is to actually hide the method:

function Product(){
  1.     var partNum; // private part number, use accessors
  2.     this.setPartNum = function(){
  3.         // as above
  4.     }
  5.     this.getPartNum = function(){
  6.         return partNum;
  7.     }
  9.     function superSecretInternalMethod(){
  10.         // Whatever your coding-ninja heart desires
  11.         // I can access partNum
  12.     }
  13. }
  15. var truck = new Product;
  16. truck.superSecretInternalMethod(); // JS Error: truck.superSecretInternalMethod is not a function.

We can even go a step farther and define private class methods and variables, but this post is already long enough, and it’s rare I have material for two in a row, so I’ll save that for next time.

If you haven’t read it, go get Pro JavaScript Design Patterns. You won’t regret it.