the Future of the Web
  • Articles
  • 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);
    }
    
    View 5 Comments | Add a comment
  • Comments

    1. Georges Jentgen at 12: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 5: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 6:22pm on August 30, 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 4: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 3: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

    Commenting is now closed.

  • Jesse Skinner

    Jesse Skinner
    • About Me
    • Email Me
    • RSS Feed RSS Icon
    • @JesseSkinner
  • Recent Articles

    • Coding with Jesse
    • Deciphering Usability
    • Free eBook: Unobtrusive Ajax
    • Official jQuery Templating Plugin
    • jQuery Live Events
    • buttons need type="submit" to submit in IE
    • Use Arrays in HTML Form Variables
    • 5 Reasons Freelancers Can Succeed in a Shrinking Economy
    • Keeping a Live Eye on Logs
    • Using PHP's empty() Instead of isset() and count()
    • See All...
  • Categories

    • javascript (41)
    • about (17)
    • links (17)
    • web (14)
    • html (12)
    • server (11)
    • css (9)
    • browsers (8)
    • carnival (7)
    • work (5)
    • ads (4)
    • events (4)
    • standards (4)
    • design (4)
    • seo (4)
  • Older Articles

    • December 2014
    • September 2013
    • October 2010
    • February 2009
    • January 2009
    • December 2008
    • November 2008
    • October 2008
    • July 2008
    • June 2008
    • 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 © 2019 The Future of the Web