Month: June 2015

What is Closure?

What is closure? If you’ve worked with languages like C and C++ before coming to JavaScript, it may be unexpected behavior. If you’re learning JavaScript as your first programming language, you may not even be aware it’s happening.

If we declare a global variable in JavaScript, it’s accessible from within any of the functions we define and lives as long as out program is running. If we declare a variable within a function, it’s only accessible from within that function and only lives until the function has finished executing.

var count = 0; // A global variable

function incrementCounter() {
    // We can access the global "count" variable
    // and the local "oldValue" variable in here.
    var oldValue = count;
    count++;
    console.log("Count bumped from " + oldValue +
                " to " + count);
    // Once we're done in here, "oldValue" goes away.
}

This behavior shouldn’t be surprising, but an example of closure might be. JavaScript allows us to define functions within other functions. We can even define functions within those functions within functions and so on. These nested functions are where we can run into instances of closure.

function Counter() {
    this.count = 0;

    this.increment = function () {
        this.count++;
    }
}

This is a simple constructor function for a Counter object where the increment function is intended to bump the value of the count variable. But there’s an alternate way to write this constructor function that may better serve its intended purpose. If someone tried to use this Counter object as follows, they will run into a problem.

var c = new Counter();
setInterval(c.increment, 1000);

The intention is obviously to increment the counter’s value every second, but can you see why this won’t work? If not, you may want to review this post on using this. Here’s an alternate implementation that will work with the setInterval example.

function Counter() {
    var count = 0;

    this.getCount = function () {
        return count;
    }

    this.increment = function () {
        count++;
    }
}

The object’s count property has been replaced by a local variable within the constructor function and we’re referencing that local variable from within the two nested functions. This is closure at work. JavaScript not only allows a function to access its own local variables, but it also allows a function to access any local variable declared within any other functions that enclose it. The getCount and increment functions can access their own local variables, any local variables defined in functions that contain them, and any global variables. One advantage of using closure with the count variable is that it removes the need to use this within the getCount and increment functions (so they are slightly easier to use as callback functions). Additionally, we are ensured that only functions defined within Counter can access the count variable. It is effectively hidden from any other functions, which means it cannot be mistakenly reset or decremented from outside Counter. (On the down-side, we can’t implement getCount and increment as prototype functions.)

Typically, we expect local variables to remain in scope until a function returns, then we expect them to go away. In many languages this is always the case, but it doesn’t always happen with JavaScript.

function IntervalCounter(seconds) {
    var count = 0;
    var milliseconds = seconds * 1000;

    function getCount() {
        return count;
    }

    setInterval(function () {
        count++;
    }, milliseconds);
}

This example defines two local variables for IntervalCounter: count and milliseconds. When IntervalCounter finishes executing, milliseconds goes out of scope and is no longer accessible. However, closure ensures that count will continue to be available to getCount and the setInterval callback function.

Closure provides an effective method of data protection in JavaScript, though it’s not without its own set of risks. If you are inexperienced with JavaScript, it is possible to reference local variables that hold large objects or arrays in memory. When these variables are then referenced within enclosed functions, you may accidentally consume large blocks of memory without knowing it. As with most programming tasks, you always want to consider carefully how your program is actually working and make sure you are acting responsibly with the programming language.

This, That, and Another Thing

Once you’ve started working with JavaScript objects, you’ll quickly need to become very familiar with a special JavaScript variable: this. It’s often thought of as referring to a specific instance of an object, but it may be better thought of as providing a context for executing a function. Here’s a simple example of using this with a constructor function. Let’s say we want to create a counter object with its own increment function.

// We define a counter object with two properties: the
// count, and a function to increment the count.
function Counter() {
  this.count = 0;
  this.increment = function () {
    this.count++;
  }
}

// Here's how we call the function to increment the
// counter's value.
var counter = new Counter();
counter.increment();

Within a constructor function, this is used to refer to the new object that’s being initialized. The object will have a count property and an increment method. The increment method uses this to refer to the object’s count property. Easy-peasy, right?

Perhaps. But let’s slow down for just a second. this on line 4 and this on line 6 appear to both reference the new object – and they do – but they do so in subtly different ways. The increment method is scoped separately from the Counter constructor function. It’s this variable is actually assigned when we call the increment method on line 13 – not when we execute the constructor function. Since we call the increment method by using the dot operator on the counter variable, the increment method’s this variable references counter. Again, JavaScript does not assign this on line 6 when the object is being initialized.

So, what does all this mean? It means in that simple example, we’ve seen two ways to set the value of JavaScript’s this variable. When calling a constructor function, this references the newly created object. When calling a function through the dot operator, this references the object whose dot operator was used to call the function. This is what allows us to create prototype functions that are shared across multiple objects.

function Counter() {
  this.count = 0;
}

Counter.prototype.increment = function () {
  this.count++;
}

var counter1 = new Counter();
counter1.increment();

var counter2 = new Counter();
counter2.increment();

Clearly, the value of this within the increment function cannot be assigned using the value from within the constructor function. Rather, it references counter1 or counter2, depending on which Counter instance is used with the dot operator, thereby ensuring that we modify counter1.count or counter2.count.

However, JavaScript allows us to create more complex examples where the value of this may not be so apparent. Consider this code sample:

function Counter() {
  this.count = 0;

  setInterval(function () {
    this.count++;
  }, 1000);
}

var counter = new Counter();

After a quick glance, it looks like a Counter is initialized with a zero count and its value increments every second when the interval callback is executed. Unfortunately, that’s not actually what happens.

Every JavaScript function has its own instance of the this variable, which is independent of the this variable in any other function. In the above example, this on line 5 is independent of this on line 2 because it occurs within a different function scope. Previously, if we wanted this within a nested function to reference a particular object, we had to use that object’s dot operator when referencing the function. However, in this instance, the function is not an object property and we don’t even perform the function call. It’s being called from some unknown location inside JavaScript’s implementation of setInterval. So how can we access the object’s count property if not through this? We need to find another way to do so and a common solution is to introduce a that variable.

function Counter() {
  var that = this;
  this.count = 0;

  setInterval(function () {
    that.count++;
  }, 1000);
}

JavaScript allows a function to access any variable that exists within its own scope – or within any scope that encloses that function (a feature called closure). In this example, the anonymous callback function is enclosed by the Counter constructor function, which means the callback can reference any variables declared within Counter(). Though the callback can’t reference Counter's this variable directly (since it’s been hidden by the callback’s own this variable, if we assign Counter's this variable to some other variable (i.e. that), we can access the count property through the other variable. It is a common practice in JavaScript to declare a that variable for the purpose of referencing an object from within enclosed functions. (A popular alternate name used instead of that is self, but it can really be any name you might choose – it’s just a normal variable.)

But if every function has its own this variable, what does this actually reference within the callback function? Well, it may depend. Often, callback functions are executed such that this refers to JavaScript’s window object. In the case of setInterval, that’s exactly what happens. This is why it can be helpful to think of this as providing a context for a function’s execution rather than referencing a particular type of object instance. The callback function may be executed within the context of the entire browser window instead of within the context of a specific object instance. It’s even possible that a function will be executed within other contexts as well, depending on how the function is actually being invoked. The popular jQuery library was designed to invoke event callback functions such that this references the particular DOM element that generated the event.

As a way of avoiding unexpected this assignments in callback functions, JavaScript does provide a way to bind a function to a particular value of this.

function Counter() {
  this.count = 0;

  setInterval(function () {
    this.count++;
  }.bind(this), 1000);
}

In this code sample, the function that is passed to setInterval has a small tweak. Following the function’s closing curly brace, it has been bound to the value of this from the constructor function. The value that’s passed to the bind function will be assigned to the this variable within the callback function. This is one way to avoid any surprises with callback functions without creating a that variable.

There is much more that could be said about this and callback functions. Hopefully, this brief introduction will at least help you remember that functions may need to use this, but sometimes that, and maybe even another thing entirely. It all depends on your context.

Working with Forms in Two Functions

Interacting with forms – it’s a common need in JavaScript apps. You need to gather information from the form when it’s submitted; you need to initialize a form when it’s first displayed to the user. Here’s a simple form:

<form id="user">
    <input type="text" name="first-name" />
    <input type="text" name="last-name" />
    <input type="submit" name="submit" value="Submit" />
</form>

One way to gather the information would be to retrieve each input value individually.

var elements = document.forms["user"].elements;
var firstName = elements["first-name"].value;
var lastName = elements["last-name"].value;

But that soon becomes tedious as the size of the form grows. What we really want is a function that will allow us to easily retrieve all the data from a form. Something that might be used like this:

var userData = readFormData("user");
var name = userData["first-name"] + " " +
           userData["last-name"];

In a single function call, we could have all the inputs gathered into a JavaScript object. We could also conceive of a function that would write the data from a JavaScript object back into the form.

writeFormData("user", userData);

So, how would we implement such functions?

function readFormData(formIdOrName) {
    var formData = {};
    var elements = document.forms[formIdOrName].elements;
    for (var index = 0; index < elements.length; ++index) {
        var name = elements[index].name;
        formData[name] = elements[index].value;
    }
    return formData;
}

function writeFormData(formIdOrName, formData) {
    var elements = document.forms[formIdOrName].elements;
    for (var index = 0; index < elements.length; ++index) {
        var name = elements[index].name;
        elements[index].value = formData[name];
    }
}

After calling readFormData, the userData object might look something like this:

userData = {
    "first-name": "John",
    "last-name": "Smith"
}

The name attributes from the form elements have been used as property names and the value properties from the form elements have been assigned to those property names. But what if we want to add a checkbox to the form – will our functions still work? Not yet. Checkbox inputs store their state in the element’s checked property instead of the value property, so we need to do a bit more work. A couple of additional functions will help us gather information from checkboxes, dropdown lists, etc..

function getElementData(element) {
    // Special handling for <select> elements
    if (element.tagName === "SELECT") {
        return getElementSelections(element);
    }
    // Special handling for checkboxes and radio buttons
    if ((element.type === "checkbox") ||
        (element.type === "radio")) {
        return element.checked;
    }
    return element.value;
}

function getElementSelections(element)
{
    // Look at all the <option> elements and return the
    // selected options.
    var values = [];
    for (var index = 0; index < element.options.length;
         ++index)
    {
       if (element.options[index].selected) {
           if (element.multiple) {
               // Multiple selections are returned in
               // an array.
               values.push(element.options[index].value);
           } else {
               // Single selections are just returned as
               // a string.
               return element.options[index].value;
           }
       }
    }
    return values;
}

function setElementData(element, data) {
    if (element.tagName === "SELECT") {
        return setElementSelections(element, data);
    }
    if ((element.type === "checkbox") ||
        (element.type === "radio")) {
        element.checked = data;
    }
    element.value = (data === undefined) ? "" : data;
}

function setElementSelections(element, data)
{
    // If the data isn't submitted as an array, we can
    // create an array of one element to simplify the
    // selection logic.
    if (!(data instanceof Array)) {
        data = [data];
    }
    for (var index = 0; index < element.options.length;
         ++index)
    {
      if(data.indexOf(element.options[index].value) >= 0) {
        element.options[index].selected = true;
      }
    }
}

Now, with a couple of tweaks to our read and write functions, we can easily transfer data between a form and a JavaScript object.

function readFormData(formIdOrName) {
    var formData = {};
    var elements = document.forms[formIdOrName].elements;
    for (var index = 0; index < elements.length; ++index) {
        var name = elements[index].name;
        formData[name] = getElementData(elements[index]);
    }
    return formData;
}

function writeFormData(formIdOrName, formData) {
    var elements = document.forms[formIdOrName].elements;
    for (var index = 0; index < elements.length; ++index) {
        var name = elements[index].name;
        setElementData(elements[index], formData[name]);
    }
}

Combined with JSON.parse, JSON.stringify, and some AJAX calls, readFormData and writeFormData can be used to easily send and receive form data between the browser and a web server. We can even package everything up into a nicely wrapped object to look something like this:

function FormData(formIdOrName) {
    this.form = document.forms[formIdOrName];
}

FormData.prototype.readData = function () {
  ...
}

FormData.prototype.writeData = function (data) {
  ...
}

var userFormData = new FormData("user");
var userData = userFormData.readData();

Hopefully, this will simplify some of your work with forms in JavaScript. You can experiment with the final sample code on CodePen.