the Future of the Web
  • Home
  • Hire Us
  • Articles
  • About
  • Contact
  • Private JavaScript Variables

    Aug 26 2007

    I find myself needing to generate unique IDs in JavaScript a lot lately. Mostly this happens when I'm creating a lot of elements dynamically and I need to assign some unique ID to them so that I can find them later. And I need to do this because I've realised that storing pointers to elements in JavaScript uses a LOT more memory than just storing the ID of an element and finding it later with getElementById().

    So anyway, what's a good way of generating unique IDs?

    A simple way is to just keep a counter going and increment it every time you access it, like this:

    var guid_counter = 0;
    
    for (var i=0;i < 100;i++) {
        // create a new <div> element
        var div = document.createElement('div');
    
        // assign a unique ID and increment counter
        div.id = 'div_' + (guid_counter++);
    
        // append to the page
        document.body.appendChild(div);
    }
    

    With this you'll end up with 100 <div>s with IDs from "div_0" to "div_99". But our guid_counter is just sitting out there in the open! Someone could come along (like us making a typo) and write guid_counter = 0 or guid_counter-- and mess everything up! We could end up with 2 elements with the same ID!

    We can improve on this by using a private variable. Private variables give us more control over global variables like our guid_counter, because we can choose when and how they are accessed and updated. Let's create a function which contains our guid counter as a private variable:

    // 'guid' is assigned to the return value of this outer function
    var guid = (function() {
        // same guid counter, but we keep it hidden inside here
        var guid_counter = 0;
    
        // return a function that has access to guid_counter
        return function() {
            // whenever guid() is called, return and increment the counter
            return guid_counter++;
        };
    
    })(); // note the () - this executes the outer function right now!
    

    If this is the first time you're seeing this syntax (or the hundredth) it can be a bit confusing. Really, we're doing the same thing as this:

    function generate_guid_function() {
        // nothing outside of generate_guid_function() can access this
        var guid_counter = 0;
    
        // return a function that has access to guid_counter
        return function() {
            // return and increment the counter
            return guid_counter++;
        };
    }
    
    // 'guid' is assigned to return value of generate_guid_function()
    var guid = generate_guid_function();
    

    The magic of all this is in JavaScript Closures. The inner function has access to guid_counter because of where it's defined, but our code outside has no way to change or access guid_counter. This is exactly like private instance variables in Java and other languages.

    Now, we can safely rely on our guid() function to generate unique IDs without worrying about our guid_counter being touched:

    for (var i=0;i < 100;i++) {
        // create a new <div> element
        var div = document.createElement('div');
    
        // assign a unique ID from our new guid() function
        div.id = 'div_' + guid();
    
        // append to the page
        document.body.appendChild(div);
    }
    
    Tags: javascript private variables
    View 5 Comments | Add a comment
  • Comments

    1. Georges Jentgen at 6:21pm on August 26, 2007

    Very nice!!! But still, if you try to write all your code "OO"-like, you will end up with quite the same code except that you do not have the initial problem your facing right now :)

    Still a very clever solution!!!

    2. Jesse Skinner at 11:19am on August 27, 2007

    @Georges - depends on the size and complexity of the code. I'm working on some projects that have over 10,000 lines of JavaScript (not counting JavaScript libraries) - without using some sort of OO we'd end up with hundreds or thousands of global functions!

    3. Sridhar at 12:22am on August 31, 2007

    Here's an alternative piece of code that's perhaps a little more intuitive in notation:

    <pre>
    function IdGenerator() { // The id generator object
        var lastId = 0;
        this.generateId = function () {
            return "div_" + (lastId++);
        }
        return this;
    }

    var theGenerator = new IdGenerator(); // Create an instance of the generator
    </pre>

    And now you can generate new ids via:

    <pre>
    var newId = theGenerator.generateId();
    </pre>

    4. Muffy at 10:10pm on September 4, 2007

    > Someone could come along (like us making a typo) and write
    > guid_counter = 0 or guid_counter-- and mess everything up! We
    > could end up with 2 elements with the same ID!

    Well, duh! So how is a global function with *any* name any less
    vulnerable? Someone could come along (like us making a typo)
    and write generate_guid_function = 0 and *still* mess everything
    up!

    5. know it all at 9:42pm on September 30, 2007

    Well, double duh. calling an undefined function is trapped while assigning an undefined var just creates it and you don't know what happened

    Add a Comment

    Note: HTML tags and entities will be converted so that they are displayed as you type them. This means if you type in <em>, people will see <em>, and if you type &lt;em&gt;, people will see &lt;em&gt;.

  • Request a Quote

  • Jesse Skinner

    Jesse Skinner
    • Hire Me
    • About Me
    • Email Me
    • RSS Feed RSS Icon
  • Recent Articles

    • Parse Accept-Language to detect a user's language
    • Twitter
    • Three years of The Future of the Web
    • Saving data to a file with PHP
    • Easy web scraping with PHP
    • See all the articles
    • IBM: Where and when to use Ajax
    • Code Igniter 1.6.0 Released
    • Update a Dev Site Automatically with Subversion
    • JavaScript Functions are Variables
    • See All...
  • Categories

    • javascript (37)
    • links (19)
    • about (18)
    • web (14)
    • server (10)
    • html (10)
    • css (8)
    • carnival (7)
    • browsers (7)
    • design (4)
    • seo (4)
    • ads (4)
    • standards (4)
    • events (4)
    • work (4)
  • Older Articles

    • May 2008
    • April 2008
    • February 2008
    • January 2008
    • December 2007
    • November 2007
    • September 2007
    • August 2007
    • July 2007
    • June 2007
    • May 2007
    • April 2007
    • March 2007
    • February 2007
    • January 2007
    • December 2006
    • November 2006
    • October 2006
    • September 2006
    • August 2006
    • July 2006
    • June 2006
    • May 2006
    • April 2006
    • March 2006
    • February 2006
    • January 2006
    • December 2005
    • November 2005
    • October 2005
    • September 2005
    • August 2005
    • April 2005
    • See All...
Copyright © 2008 Jesse Skinner | CSS | XHTML | RSS | Help | Impressum | Cutie Quilts | Internet Blog Top Sites