Javascript Concepts

Google Maps API Tutorial

Javascript Concepts: Function Closure

Function closure is a fairly unusual computer language concept so it may take you by surprise if you’re familiar with other programming languages.

What happens is that each time a function closes, a copy of the values of its local variables is retained. Technically, a copy of the function’s “activation frame” is retained, and that contains all the local variables.

The key feature of function closure is that any callback functions (such as event handlers) which were created when the function executed will have access to the preserved activation frame, and its local variables.

Activation Frame

Activation frames do occur in other languages that support recursive functions. Consider this code

    function factorial(a) {
      if (a == 1) {return 1}
      else {return a*factorial(a-1)}
    }

When you call “factorial(5)”, then five separate instances of the factorial() function get executed, each one has its own activation frame, which contains its own local variables. In particular, each instance of the function has its own value for “a”.

Memory

If a function closes without creating a callback function, then, in a properly written browser, its activation frame will eventually be destroyed by the Garbage Collection system, and the memory recovered.

The variables are only retained if something continues to hold accessible references to them.

Closure

Note that the value of the variable that is retained is the value at the time that the function closed, not the value at the time that the callback function was created.

Updating closure variables

A callback function can change the values of variables in the activation frame of the closed function. It can’t, however, create new variables in that activation frame.

   function f1() {
      var foo=123;
      GEvent.addListener(map,"click",function(overlay,point) {
        GLog.write(foo);
        foo++;
      });
      var foo=321;
    }

The first time the map is clicked, the value “321” will be displayed (the value of “foo” when the function closed).

The second time the map is clicked, the value “322” will be displayed. The value of “foo” in the activation frame has been updated by the previous click callback.

Advertisements

Javascript Concepts

Google Maps API Tutorial

Javascript Concepts: Asynchronous I/O

In most computer languages, when you tell the program to read or write some data, the processing pauses until that action completes. The results of the read operation are available for use by the next statement in the program.

Most read and write operations in Javascript don’t work like that. Javascript makes a request to the I/O system for the data to be read or written and then continues to execute the following statements without waiting for the action to complete. When the action is completed, a corresponding completion event will be triggered.

If you want to be informed of the I/O completion, e.g. if you want to process the data that’s been read, you have to supply a callback function which will be called when the I/O completes. Or, in some cases, listen for an event that indicates that the operation is complete.

This makes sense when you consider that I/O operations which involve exchanging packets of data with Internet servers in distant parts of the world may take thousands of times longer to complete than I/O operations on your local peripherals. If the browser waited for one image to load before requesting the next, then it would take an awful lot longer for all the images to be displayed.

Images

Most of the time when you load an image, you’re not interested in knowing when the I/O has completed. In those cases when you do care, you can add an “onload” attribute to the <img> specifying the action to be performed when the image fetch is completed.

Alert

One example of an operation which is not asynchronous is “alert”. when you call alert(), all processing is paused until the user clicks the alert window’s “OK” button.

GDownloadUrl, GClientGeocoder and GDirections

GDownloadUrl, GClientGeocoder and GDirections calls are always asynchronous. There’s nothing you can do to make them synchronous.

The results of the I/O are not available immediately after the GDownloadUrl() call, but only within its callback function.

The results of a GDirections call are only available wne its “load” event has been triggered.

GXmlHttp

The method of using GXmlHttp() described in the documentation uses asynchronous processing.

If you really want to, you can use GXmlHttp() in synchronous mode. This is achieved by setting the third parameter of request.send() to false

     var request = GXmlHttp.create();
      request.open("GET", "example.xml", false);
      request.send(null);
      var xmlDoc = request.responseXML;

When used in this way, the “request.send()” will cause the processing to pause until the file has been fetched.

This works in standards-compliant browsers which don’t support ActiveX, and in MSIE6. There’s no guarantee that it will work in any other browsers that support ActiveX.

[The way the code works is that if the browser supports ActiveXObject, then GXmlHttp() calls ActiveXObject(“Microsoft.XMLHTTP”), if not, then if the browser supports window.XMLHttpRequest, then GXmlHttp() calls that. MSIE7 supports both technologies. The API is currently coded to use ActiveX if both are available. I’ve not tested synchronous GXmlHttp in MSIE7.]

onload functions

Another common situation where an asynchronous operation happens is when you use an onload function, either by writing <body onload=”load()”> in the HTML, or equivalently by writing window.onload=load;in the Javascript.

Code that’s placed outside any such function is executed as soon as the browser reads it, then the browser fetches any asyncronous resources that the page requires, in particular the images. After all the image fetches complete, the browser calls the onload function.

Javascript Concepts

Google Maps API Tutorial

Javascript Concepts: Scope

In common with most modern computer languages, Javascript variables and functions have “scope”. What this means is that the variable or function can only be accessed from within the function that “var”ed it.

In languages without scope, such as early versions of BASIC and COBOL, people working on different parts of the same program had to be careful not to use the same variable for different purposes. If Fred wrote a useful BASIC subroutine that used the variable “A”, and Dave incorporated that subroutine into one of his programs that also happened to use a variable called “A”, then calling the subroutine would change the value of “A” which might cause Dave’s program to behave incorrectly in a completely different part of the code that expected the original value.

In a scoped language, Fred can write a function that uses separate “local” variables which only exist inside that function, and there’s no danger of them clashing with “global” variables of the same name that exist in the calling program.

If you really really want to, you can explicitly access the global variable, by referring to it like “window.A”. Global variables are properties of the “window” object.

Undeclared variables

If you assign a value to a variable without first “var”ing it, then a global variable of that name is created for you.

In MSIE, there’s a conflict with the fact that it already creates a global variable that matches the “id” of each element that has an “id”. Attempting to assign a new value to a variable that MSIE created that way, without using “var”, will throw an error.

Not block structured

If you’re familiar with block-structured languages, such as C, Pascal and Java, then you might possibly be caught out by the fact that Javascript is not block-structured. Variables that are created inside blocks (such as for loops and if statements) persist until the end of the function. For example, if you’re used to a block-structured language, you might expect variable in this example to display the value “123”.

   function foo() {
     var i=123;
     for (var i=0; i<3; i++) {
       ...
     }
     alert(i);
   }

In Javascript, the value displayed is “3”. That’s because “i” is local to the function, not local to the “block”, so the “i” used inside the for is the same as the one declared outside the for loop.

Note that Javascript doesn’t complain if you “var” the same variable more than once within the same scope.

Calling Javascript from HTML

Whenever you make calls from HTML to Javascript, e.g. from the “onclick” of a button, the called Javascript executes in global context. This means that any functions or variables referenced in the “onclick” string must be global.

Local functions

In the same way that variables can be local to a function, functions can be local to another function.

It’s all to easy to do this by mistake if you change your code from something that runs inline to something that’s called from <body onload=”loadMap()”>. You can’t just wrap “function loadMap() {” … “}” around the whole of your code and expect it to work because functions that were previously global will have become local functions of loadMap().