How to create an object with private variables and methods

In short, you can use private variables when you return another scope when declaring a class.

  1. function Cats() {
  2.   var nameList = []; // private var
  3.        
  4.   // This is where you define another scope!
  5.   return {
  6.     add:function(name) {
  7.       nameList.push(name);
  8.     }
  9.   }     
  10. }

How does it work?

The magic lies in creating a different scope at the end of the class definition that does not include private variables. Then, private members are available in this scope and not outside of it, thanks to the power of closures.

Differences between private and public

These two classes definition shows the difference between the a class where all members are public versus a class where some members are private.

This is a class where all members are public.

  1. function PublicCats() {
  2.   // This is the list of cat names
  3.   this.nameList = [];
  4.  
  5.   // This is a method that I would like to be private but can’t
  6.   // It returns the last cat of the list
  7.   this.lastCat = function() {
  8.     return this.nameList[this.nameList.length-1];
  9.   }
  10.  
  11.   // Return the list of names
  12.   this.names = function() {
  13.     return this.nameList;
  14.   }
  15.  
  16.   // Add a name to the list
  17.   this.add = function(name) {
  18.     this.nameList.push(name);
  19.    
  20.     // Return the last cat just added
  21.     return this.lastCat();
  22.   }  
  23. }

This is the corresponding class where some members are private.

  1. function PrivateCats() {
  2.   // This is the list of cat names
  3.   var nameList = [];
  4.  
  5.   // This is a private method
  6.   var lastCat = function() {
  7.     // Note : I don’t use "this" to access private variables
  8.     // thanks to the power of closures!
  9.     return nameList[nameList.length-1];
  10.   }
  11.  
  12.   // These are our public methods!
  13.   // This is where we create another scope to
  14.   // avoid external objects to use the private variables.
  15.   return {
  16.     add:function(name) {
  17.       // Note : once again, I don’t use "this"
  18.       // to access the private variables and methods
  19.       nameList.push(name);
  20.       return lastCat();
  21.     },
  22.     names:function() {
  23.       return nameList;
  24.     }
  25.   }  
  26. }

In the above code, line 15 makes all the difference between the two classes.

On GitHub

Get all the code on GitHub and see it live in action on my GitHub page.

Comments

  1. [...] [UPDATE : This post is outdated. Check out the new post on how to create objects.] [...]

  2. # Topper September 23, 2009 at 11:07:03

    The only thing about specifying your scope in the return object, is that it can be confusing to read (or see where public vs private stops… this is totally just a semantic quibble but:

    function PrivateCats() {
    var klass = {};

    var privateFunction = function () {};

    klass.publicFunction = function () {};

    return klass;
    }

    Seems to be a little easier to read.

  3. # Dan (maintainer of Javascript Kata) September 23, 2009 at 13:15:14

    @Topper There’s a hundred ways of assigning functions and I picked the easiest one to understand but it may be hard to read when the class grows. Sometimes, I use _privateMethod() to distinguish them easily from public methods but I’m not decided if I should really use this notation.

    Anyways, thanks for your thoughts! Someone that would read the comments would see other ways to do it.

  4. # Yansky September 24, 2009 at 04:26:18

    I don’t see the advantage to using private variables as opposed to namespacing. Sure it may be accessible outside of the function, but the fact that it’s namespaced means there wont be any problems with variable name collisions right?
    e.g.

    function foo(){
    foo.bar={};
    }

    var bar={}; //no collision

  5. # Dan (maintainer of Javascript Kata) September 24, 2009 at 09:13:57

    @Yansky It’s less about collisions and more about cleaner code. If all the methods of an object are public, it could be a harder for other programmer to use your code.

  6. # BK September 25, 2009 at 15:33:40

    Scoping variables is one of the base OO principle: encapsulation. This is the main reason I think to do it.

    Also, why not simply do

    function PrivateCats() {
    // This is the list of cat names
    var nameList = [];

    // This is a private method
    var lastCat = function() {
    // Note : I don’t use “this” to access private variables
    // thanks to the power of closures!
    return nameList[nameList.length-1];
    }

    // These are our public methods!
    // This is where we create another scope to
    // avoid external objects to use the private variables.
    this.add = function(name) {
    // Note : once again, I don’t use “this”
    // to access the private variables and methods
    nameList.push(name);
    return lastCat();
    },
    this.names = function() {
    return nameList;
    }
    }

    Seems even more simple I think… And works the same since this isn’t in the same scope as the var declarations. Maybe I missed something… I’m starting to become rusted in JS :P

  7. # BK September 25, 2009 at 15:35:38

    Oups… Forgot to remove the return line :P

    Simpler sample:

    function test(){
    var rot=”a”;
    this.rotted=function(){return rot};
    }
    var test2 = new test()
    alert(test2.rot); //returns undefined
    alert(test2.rotted()); //returns a

  8. # BK September 25, 2009 at 15:36:48

    Forgot to remove the “return” line.

    Here is a simpler example:

    function test(){
    var rot=”a”;
    this.rotted=function(){return rot};
    }

    var test2 = new test()
    alert(test2.rot); //Returns undefined
    alert(test2.rotted()); //Returns a

  9. # Dan (maintainer of Javascript Kata) September 25, 2009 at 16:01:20

    @BK You could do it that way to. I just prefer the other notation… thanks for commenting about this way of doing things.

    Keep them coming, I’ll probably write a post about how many different ways of using private variables in an object ;)

  10. [...] the new solution using a private variable for the [...]

  11. # boiledwater October 29, 2009 at 03:40:05

    yes,the essential is closure!

Post a comment

Comments are moderated and innapropriate ones won't be approved. Please respect this public space.